数据结构的归并排序(c语言版)

news2025/1/17 23:23:12

 

一.归并排序的基本概念

1.基本概念

归并排序是一种高效的排序算法,它采用了分治的思想。它的基本过程如下:

  1. 将待排序的数组分割成两个子数组,直到子数组只有一个元素为止。
  2. 然后将这些子数组两两归并,得到有序的子数组。
  3. 不断重复第二步,直到最终得到有序的整个数组。

2.核心思想

归并排序的核心是"分而治之"的思想。通过不断地将数组拆分成更小的子数组,直至子数组只有一个元素,然后再将这些有序的子数组合并起来,最终得到一个有序的数组。

与简单的冒泡排序或选择排序相比,归并排序的时间复杂度为O(nlogn),这使它能够高效地处理大规模的数据集。虽然它需要O(n)的额外空间来存储中间结果,但其优秀的时间复杂度使其成为处理大数据量排序问题的首选算法之一。

总的来说,归并排序是一种强大而高效的排序算法,它体现了分治策略在算法设计中的重要应用。如果您有任何其他问题,欢迎随时向我咨询。

3.优点

优点:

  1. 时间复杂度稳定:归并排序的时间复杂度为O(nlogn),不管输入数据的初始状态如何,时间复杂度都是稳定的。这使它能够高效处理大规模数据。

  2. 稳定排序:归并排序是一种稳定的排序算法,也就是说,当两个相等的元素出现时,它们在输出序列中的相对顺序与输入序列中的相对顺序一致。这对某些应用场景很重要。

  3. 并行计算友好:归并排序的"分而治之"特性使得它很容易并行化,在多核处理器上可以获得很好的性能提升。

4.缺点

缺点:

  1. 需要额外空间:归并排序需要额外的内存空间来存储中间结果,空间复杂度为O(n)。这可能成为一个瓶颈,尤其是在内存受限的环境中。

  2. 数据交换频繁:归并排序需要频繁地将数据从输入数组复制到临时数组,这在某些情况下可能会降低性能。

  3. 无法就地排序:归并排序无法在原数组上就地排序,需要使用额外的空间。这对于某些内存受限的场景可能是个问题。

二.归并排序的功能

归并排序的基本功能就是对一组数据进行排序。具体来说,它可以实现以下几个功能:

  1. 将无序的数组或列表排序为有序的数组或列表。归并排序可以将任意大小的输入集合有效地排序,包括大型数据集。

  2. 保持数据的相对位置关系。如果输入数据中存在相等的元素,归并排序会保留它们原有的相对顺序,这在某些应用场景中很重要。

  3. 支持并行计算。由于归并排序的"分而治之"特性,它非常适合在多核处理器上并行执行,从而获得大幅的性能提升。

  4. 可以用于外部排序。当数据量太大无法一次性装入内存时,可以采用外部排序的方式,先将数据划分成多个小块,然后使用归并排序分别对这些小块进行排序,最后合并这些有序块。

  5. 可以作为其他算法的子过程。归并排序常被用作其他算法的核心步骤,比如快速排序、外部排序等。

归并排序是一种通用且高效的排序算法,它在各种规模和类型的数据排序中都有重要应用。它的功能十分强大,能够满足绝大多数排序需求。

三.归并排序的代码实现

1.合并两个有序数组

  1. 定义三个索引变量 ijk,分别用来遍历左数组、右数组和目标数组。
  2. 使用 while 循环比较左右数组当前元素的大小,将较小的元素依次添加到目标数组中。
  3. 当左数组或右数组中还有剩余元素时,将它们依次添加到目标数组的末尾。
// 合并两个有序数组
void merge(int arr[], int left[], int left_size, int right[], int right_size, int size) {
    int i = 0, j = 0, k = 0;
    while (i < left_size && j < right_size) {
        if (left[i] <= right[j]) {
            arr[k++] = left[i++];
        } else {
            arr[k++] = right[j++];
        }
    }
    while (i < left_size) {
        arr[k++] = left[i++];
    }
    while (j < right_size) {
        arr[k++] = right[j++];
    }
}

2.递归实现

  1. 首先,它检查数组大小是否小于等于 1,如果是,则直接返回,因为单个元素已经是有序的了。

  2. 接下来,它将数组分为两个子数组:左子数组 left 和右子数组 right。计算中点 mid 作为分割点,将原数组 arr 分为左右两部分。

  3. 然后,它将原数组 arr 的元素复制到左右两个临时数组 left 和 right 中。

  4. 递归地对左右两个子数组分别调用 merge_sort 函数,对它们进行排序。

  5. 最后,它调用 merge 函数,将已经排序的左右子数组合并回原数组 arr

// 递归实现归并排序
void merge_sort(int arr[], int size) {
if (size <= 1) {
return;
}
int mid = size / 2;
int left[mid];
int right[size - mid];
for (int i = 0; i < mid; i++) {
left[i] = arr[i];
}
for (int i = mid; i < size; i++) {
right[i - mid] = arr[i];
}
merge_sort(left, mid);
merge_sort(right, size - mid);
merge(arr, left, mid, right, size - mid);
}

3.非递归实现

  1. 首先,它申请了一个临时数组 temp,用来存储合并后的有序子数组。这是非递归实现所需要的额外空间。

  2. 然后,它使用一个外层循环来控制子数组的宽度 width。初始值为 1,每次翻倍,直到 width 大于等于数组大小 size

  3. 内层循环遍历数组,每次处理长度为 2 * width 的两个相邻子数组。

  4. 对于每个子数组对,它计算左子数组的长度 left_size 为 width,右子数组的长度 right_size 可能会小于 width (当剩余元素不足 width 时)。

  5. 然后调用 merge 函数,将左右两个有序子数组合并为一个有序子数组,存储在原数组 arr 中。

  6. 最后,释放临时数组 temp 占用的动态内存。

// 非递归实现归并排序
void iterative_merge_sort(int arr[], int size) {
    int *temp = (int *)malloc(size * sizeof(int));
    if (!temp) {
        printf("Memory allocation failed.\n");
        return;
    }

    for (int width = 1; width < size; width *= 2) {
        for (int i = 0; i < size; i += 2 * width) {
            int left_size = width;
            int right_size = (i + 2 * width < size) ? width : size - i - width;
            merge(arr + i, arr + i, left_size, arr + i + width, right_size, size);
        }
    }

    free(temp);
}

四.归并排序的源代码

1.递归

#include <stdio.h>
#include <stdlib.h>

// 合并两个有序数组
void merge(int arr[], int left[], int left_size, int right[], int right_size) {
    int i = 0, j = 0, k = 0;
    while (i < left_size && j < right_size) {
        if (left[i] <= right[j]) {
            arr[k++] = left[i++];
        } else {
            arr[k++] = right[j++];
        }
    }
    while (i < left_size) {
        arr[k++] = left[i++];
    }
    while (j < right_size) {
        arr[k++] = right[j++];
    }
}

// 递归实现归并排序
void merge_sort(int arr[], int size) {
    if (size <= 1) {
        return;
    }
    int mid = size / 2;
    int left[mid];
    int right[size - mid];
    for (int i = 0; i < mid; i++) {
        left[i] = arr[i];
    }
    for (int i = mid; i < size; i++) {
        right[i - mid] = arr[i];
    }
    merge_sort(left, mid);
    merge_sort(right, size - mid);
    merge(arr, left, mid, right, size - mid);
}

int main() {
    int arr[] = {5, 2, 4, 6, 1, 3, 2, 6};
    int size = sizeof(arr) / sizeof(arr[0]);
    merge_sort(arr, size);
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

2.非递归

#include <stdio.h>
#include <stdlib.h>

// 合并两个有序数组
void merge(int arr[], int left[], int left_size, int right[], int right_size, int size) {
    int i = 0, j = 0, k = 0;
    while (i < left_size && j < right_size) {
        if (left[i] <= right[j]) {
            arr[k++] = left[i++];
        } else {
            arr[k++] = right[j++];
        }
    }
    while (i < left_size) {
        arr[k++] = left[i++];
    }
    while (j < right_size) {
        arr[k++] = right[j++];
    }
}

// 非递归实现归并排序
void iterative_merge_sort(int arr[], int size) {
    int *temp = (int *)malloc(size * sizeof(int));
    if (!temp) {
        printf("Memory allocation failed.\n");
        return;
    }

    for (int width = 1; width < size; width *= 2) {
        for (int i = 0; i < size; i += 2 * width) {
            int left_size = width;
            int right_size = (i + 2 * width < size) ? width : size - i - width;
            merge(arr + i, arr + i, left_size, arr + i + width, right_size, size);
        }
    }

    free(temp);
}

int main() {
    int arr[] = {5, 2, 4, 6, 1, 3, 2, 6};
    int size = sizeof(arr) / sizeof(arr[0]);
    iterative_merge_sort(arr, size);
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1790539.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MES系统生产计划的实施流程

在工厂的生产运营中&#xff0c;首先需要制定生产计划&#xff0c;MES系统软件可以监控从原材料进入工厂到产品进入仓库的整个生产过程&#xff0c;记录生产过程中使用的材料&#xff0c;设备&#xff0c;产品检验数据和结果&#xff0c;以及生产时间&#xff0c;人员和其他信息…

项目-双人五子棋对战:匹配模块的实现(3)

完整代码见: 邹锦辉个人所有代码: 测试仓库 - Gitee.com 模块详细讲解 功能需求 匹配就类似于大家平常玩的王者荣耀这样的匹配功能, 当玩家点击匹配之后, 就会进入到一个匹配队列, 当匹配到足够数量的玩家后, 就会进入确认页. 在这里, 我们主要实现的是1 - 1匹配功能, 首先先…

PPP-B2b精密产品使用注意事项及分析

1、因为在使用PPP-B2b进行定轨的时候&#xff0c;发的精密轨道产品是B3频点的&#xff0c;需要改正的卫星质心&#xff08;Com&#xff09;与SP3精密星历对比。 2、PPP-B2b产品吸收了电离层误差&#xff0c;因此电离层提取方面与IGS电离层完全无法对其。 3、由于PPP-B2b产品精…

【微信小程序】初识小程序

项目结构 项目基本组成结构 页面基础组成结构 JSON 配置文件 App.json app.json是当前小程序的全局配置&#xff0c;包括了小程序的所有页面路径、窗口外观、界面表现、底部tab等。 在 pages 中加入路径&#xff0c;保存后&#xff0c;开发者工具可以自动帮我们创建对应的页…

SAS:什么时候用kcompress呀?

问题&#xff1a;如何截取ECGTPT变量中的后三个字符&#xff1f; 下图展示了以k开头的以及非k开头的substr函数和length函数&#xff0c;发现在UTF-8编码下&#xff0c;仅以k开头的函数能够截取成功。 释疑&#xff08;以下内容来自SAS Help&#xff09; SAS提供的字符函数…

微软云计算[2]之微软云关系数据库SQL Azure

微软云关系数据库SQL Azure SQL Azure概述SQL Azure关键技术SQL Azure数据库SQL Azure报表服务SQL Azure数据同步 SQL Azure和SQL Server对比 SQL Azure概述 SQL Azure是微软的云中关系型数据库。 SQL Azure数据库简化了多数据库的供应和部署。 SQL Azure还为用户提供内置的高…

FPGA新起点V1开发板(九)——流水灯

文章目录 一、模块框图二、代码编写三、注意点四、总结 一、模块框图 二、代码编写 endmodule下面需要敲出一个回车代码拼接是大括号 led < {led[2:0],led[3]}注意二进制和十进制 module flow_led(input sys_clk50,input rst_n,output reg [3:0] le…

探索 Adobe Illustrator 2023 (AI 2023) for Mac/Win——创意设计的强大工具

Adobe Illustrator 2023 (AI 2023) for Mac/Win 是一款在设计领域备受推崇的专业矢量图形编辑软件软件&#xff0c;为设计师们提供了无尽的创意可能性。 它具有强大而精确的绘图功能&#xff0c;让用户能够轻松绘制出各种复杂的图形、线条和形状。无论是简洁的图标设计还是精美…

STM32作业实现(八)触摸按键TPAD

目录 STM32作业设计 STM32作业实现(一)串口通信 STM32作业实现(二)串口控制led STM32作业实现(三)串口控制有源蜂鸣器 STM32作业实现(四)光敏传感器 STM32作业实现(五)温湿度传感器dht11 STM32作业实现(六)闪存保存数据 STM32作业实现(七)OLED显示数据 STM32作业实现(八)触摸按…

vscode中选择pytorch虚拟环境中库没有导入报错,但是本机命令行下载过了

这是下载成功的结果 这个时候你会发现matplotlib的库是下载过的&#xff0c;没法下载 这个的原因是你的matplotlib库是下载到本机的python上但是pytorch框架上的是没有这个库的&#xff0c;此时应该打开ananconda promopt 然后输入activate pytorch转换成pytorch环境 然后pip…

gitlabcicd-k8s部署runner

一.环境信息 存储使用nfs挂载持久化 k8s环境 helm安装 建议helm 3 二.部署gitlab-runner 1.查看gitlab版本 进入容器可通过执行&#xff1a;gitlab-rake gitlab:env:info rootgitlab-647f4bd8b4-qz2j9:/# gitlab-rake gitlab:env:info System information System: Current Us…

zimo221软件和PCtoLCD2002软件的使用

Zimo221软件和PCtoLCD2002软件的使用 在没有字库时&#xff0c;我们可能需要自建汉字库&#xff0c;这时&#xff0c;汉字取模软件就会变得很重要。 一、zimo221取模方式&#xff1a; 1、打开软件 2、点击“基本操作” 3、一定要先点击“新建图像”按钮&#xff0c;见下图…

vue3中 window绑定scroll事件滚动页面获取不到e.target.scrollTop

遇到的问题 vue3项目 onMounted(() > {window.addEventListener(scroll, (e) > {console.log(e.target.scrollTop)}) })想要监听页面中的滚动&#xff0c;然后获取滚动距离实现一些功能&#xff0c;发现event参数中获取不到e.target.scrollTop&#xff08;印象中以前使…

NSIS 安装包默认支持的参数

NSIS 安装包默认支持的参数 NSIS 制作的安装包默认支持 /NCRC、/S、/D 三个参数&#xff0c;详见下文 3.2 Installer Usage&#xff08;来自 Command Line Usage&#xff09;。 以上三个参数对应的功能分别为禁止 CRC 校验、静默安装、设置安装路径&#xff0c;这三个功能不需…

JAVA家政系统小程序源码,家政系统源码,支持店铺入驻接单,师傅入驻接单:专业团队自主研发的一套上门家政APP系统成品源码,支持商用

JAVA家政系统小程序源码&#xff0c;家政系统源码&#xff0c;支持店铺入驻接单&#xff0c;师傅入驻接单&#xff1a;专业团队自主研发的一套上门家政APP系统成品源码&#xff0c;支持商用 家政系统是一套可提供上门家政的系统&#xff0c;可在线预约开荒保洁、上门维修、美容…

使用 Node.js 和 Azure Function App 自动更新 Elasticsearch 索引

作者&#xff1a;来自 Elastic Jessica Garson 维护最新数据至关重要&#xff0c;尤其是在处理频繁变化的动态数据集时。这篇博文将指导你使用 Node.js 加载数据&#xff0c;并通过定期更新确保数据保持最新。我们将利用 Azure Function Apps 的功能来自动执行这些更新&#xf…

Vue中引入elementUI中的container组件失效

1.不用修改官网中任何css或者html 2.按需引入&#xff0c;不是只是引入官网的就可以 import Vue from vue import Router from vue-router import HelloWorld from /components/HelloWorld import First from /components/views/First import Second from /components/views/…

操作失败——后端

控制台观察&#xff0c;页面发送的保存菜品的请求 返回的response显示&#xff1a; ---------- 我开始查看明明感觉都挺正常&#xff0c;没啥错误&#xff0c;就是查不出来。结果后面电脑关机重启后&#xff0c;隔一天看&#xff0c;就突然可以了。我觉着可能是浏览器的缓存没…

基本算法——位运算

a^b 原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目描述 运行代码 #include<iostream> using namespace std; long long a,b,c,t1; int main() {cin>>a>>b>>c;for(;b;b/2){if(b&1)tt*a%c;aa*a%c;}cout<<t%c; } 代码思路…

HTML5+CSS3+JS小实例:网格图库

实例:网格图库 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0&…