归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之),将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序,若将两个有序表合并成一个有序表,称为二路归并

1、归并排序的基本思想

将待排序序列R[0...n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的有序序列

2、归并排序的算法描述

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾,将另一序列剩下的所有元素直接复制到合并序列尾
 
归并排序其实要做两件事:

(1)“分解”——将序列每次折半划分(递归实现)

(2)“合并”——将划分后的序列段两两合并后排序

如何合并

在每次合并过程中,都是对两个有序的序列段进行合并,然后排序。

这两个有序序列段分别为 R[low, mid] 和 R[mid+1, high]。

先将他们合并到一个局部的暂存数组R2中,带合并完成后再将R2复制回R中。

我们称 R[low, mid] 第一段,R[mid+1, high] 为第二段。

每次从两个段中取出一个记录进行关键字的比较,将较小者放入R2中,最后将各段中余下的部分直接复制到R2中。

经过这样的过程,R2已经是一个有序的序列,再将其复制回R中,一次合并排序就完成了。

 
3、代码实现
  1. /* 将序列对半拆分直到序列长度为1*/
  2. void MergeSort_UptoDown(int *num, int start, int end)
  3. {
  4. int mid = start + (end - start) / ;
  5.  
  6. if (start >= end)
  7. {
  8. return;
  9. }
  10.  
  11. MergeSort_UptoDown(num, start, mid);
  12. MergeSort_UptoDown(num, mid + , end);
  13.  
  14. Merge(num, start, mid, end);
  15. }
  16.  
  17. void Merge(int *num, int start, int mid, int end)
  18. {
  19. int *temp = (int *)malloc((end-start+) * sizeof(int)); //申请空间来存放两个有序区归并后的临时区域
  20. int i = start;
  21. int j = mid + ;
  22. int k = ;
  23.  
  24. while (i <= mid && j <= end)
  25. {
  26. if (num[i] <= num[j])
  27. {
  28. temp[k++] = num[i++];
  29. }
  30. else
  31. {
  32. temp[k++] = num[j++];
  33. }
  34. }
  35.  
  36. while (i <= mid)
  37. {
  38. temp[k++] = num[i++];
  39. }
  40. while (j <= end)
  41. {
  42. temp[k++] = num[j++];
  43. }
  44.  
  45. //将临时区域中排序后的元素,整合到原数组中
  46. for (i = ; i < k; i++)
  47. {
  48. num[start + i] = temp[i];
  49. }
  50.  
  51. free(temp);
  52. }
 
4、拆分过程

(图片来源:https://www.cnblogs.com/chengxiao/p/6194356.html)

完整代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. void MergeSort_UptoDown(int *num, int start, int end);
  5. void Merge(int *num, int start, int mid, int end);
  6.  
  7. int main()
  8. {
  9. /* 归并排序(升序) */
  10. int num[] = {, , , , , , , , , };
  11. int length = sizeof(num) / sizeof(num[]);
  12. int i;
  13.  
  14. MergeSort_UptoDown(num, , length - );
  15.  
  16. for (i = ; i < length; i++)
  17. {
  18. printf("%d ", num[i]);
  19. }
  20.  
  21. return ;
  22. }
  23.  
  24. /* 将序列对半拆分直到序列长度为1*/
  25. void MergeSort_UptoDown(int *num, int start, int end)
  26. {
  27. int mid = start + (end - start) / ;
  28.  
  29. if (start >= end)
  30. {
  31. return;
  32. }
  33.  
  34. MergeSort_UptoDown(num, start, mid);
  35. MergeSort_UptoDown(num, mid + , end);
  36.  
  37. Merge(num, start, mid, end);
  38. }
  39.  
  40. void Merge(int *num, int start, int mid, int end)
  41. {
  42. int *temp = (int *)malloc((end-start+) * sizeof(int)); //申请空间来存放两个有序区归并后的临时区域
  43. int i = start;
  44. int j = mid + ;
  45. int k = ;
  46.  
  47. while (i <= mid && j <= end)
  48. {
  49. if (num[i] <= num[j])
  50. {
  51. temp[k++] = num[i++];
  52. }
  53. else
  54. {
  55. temp[k++] = num[j++];
  56. }
  57. }
  58.  
  59. while (i <= mid)
  60. {
  61. temp[k++] = num[i++];
  62. }
  63. while (j <= end)
  64. {
  65. temp[k++] = num[j++];
  66. }
  67.  
  68. //将临时区域中排序后的元素,整合到原数组中
  69. for (i = ; i < k; i++)
  70. {
  71. num[start + i] = temp[i];
  72. }
  73.  
  74. free(temp);
  75. }

归并排序(从上到下、从下到上)——C语言的更多相关文章

  1. react + iscroll5 实现完美 下拉刷新,上拉加载

    经过几天的反复折腾,总算做出一个体验还不错的列表页了,主要支持了下拉刷新,上拉加载两个功能. 一开始直接采用了react-iscroll插件,它是基于iscroll插件开发的组件.但是开发过程中,发现 ...

  2. 在SpringMVC框架下实现文件的 上传和 下载

    在eclipse中的javaEE环境下:导入必要的架包 web.xml的配置文件: <?xml version="1.0" encoding="UTF-8" ...

  3. 原生JS实现分页效果2.0(新增了上一页和下一页,添加当前元素样式)

    虽然写的很烂,但至少全部都是自己写的,因为这个没有固定的顺序,所以就没有封装,如果你技术好的话,可以你写的分享给我,谢谢. <!DOCTYPE html><html lang=&qu ...

  4. iOS MJRefresh下拉刷新(上拉加载)使用详解

    下拉刷新控件目前比较火的有好几种,本人用过MJRefresh 和 SVPullToRefresh,相对而言,前者比后者可定制化.拓展新都更高一点. 因此本文着重讲一下MJRefresh的简单用法. 导 ...

  5. js获取上一个月、下一个月格式为yyyy-mm-dd的日期

    /** * 获取上一个月 * * @date 格式为yyyy-mm-dd的日期,如:2014-01-25 */ function getPreMonth(date) { var arr = date. ...

  6. PHP实现上一篇、下一篇

    //php实现上一篇.下一篇 获取当前浏览文章id $id = isset($_GET[ ? intval($_GET['id']) : ""; 下一篇文章 $query = my ...

  7. SVPullToRefresh​ 下拉刷新,上拉加载

    https://github.com/Sephiroth87/ODRefreshControl 类似刷新控件,类似qq动画的那种刷新. 一.下载第三方库 https://github.com/samv ...

  8. Android PullToRefreshListView上拉刷新和下拉刷新

    PullToRefreshListView实现上拉和下拉刷新有两个步骤: 1.设置刷新方式 pullToRefreshView.setMode(PullToRefreshBase.Mode.BOTH) ...

  9. c++(vs上)与g++(linux下)对于++操作的汇编代码解读

    先来看一个代码,估计很多同学都碰到过其中的某一个. #include <stdio.h> #include <iostream> using namespace std; in ...

  10. ListView(2)最简单的上拉刷新,下拉刷新

    最简单的上拉刷新和下拉刷新,当listview滚动到底部时向上拉刷新数据.当listview滚动到最顶部时下拉刷新.       图1,上拉刷新 图2,下拉刷新 1,设置lisview,加载heade ...

随机推荐

  1. SkyWorking基础:6.2版本安装部署

    就在今天,SkyWorking发布了6.2版本. 概述 什么是SkyWorking SkyWalking是观察性分析平台和应用性能管理系统. 提供分布式追踪.服务网格遥测分析.度量聚合和可视化一体化解 ...

  2. Mysql常用的查询语句,记录一下,好东西大家共享

    一查询数值型数据: SELECT * FROM tb_name WHERE sum > 100; 查询谓词:>,=,<,<>,!=,!>,!<,=>,= ...

  3. Linux系统下解锁Oracle的Scott用户

    1).在Oracle用户下面输入命令:lsnrctl status查看监听是否开启,如果未开启则需要开启监听,输入命令:lsnrctl start; 2).如果没有设置监听的话需要先建立一个监听,然后 ...

  4. Java学习笔记——I/O流常用类之间的继承关系及构造方法

    朝辞白帝彩云间,千里江陵一日还. 两岸猿声啼不住,轻舟已过万重山. ——早发白帝城 总结一下有哪些I/O流: 输入流方法主要是read()和close(),输出流方法主要是write().flush( ...

  5. Go - Struct 结构体

    目录 概述 声明结构体 生成 JSON 改变数据 推荐阅读 概述 结构体是将零个或多个任意类型的变量,组合在一起的聚合数据类型,也可以看做是数据的集合. 声明结构体 //demo_11.go pack ...

  6. 09、MySQL—列属性

    列属性又称之为字段属性,在mysql中一共有6个属性:null,默认值,列描述,主键,唯一键和自动增长 1.Null属性 NULL属性:代表字段为空 如果对应的值为YES表示该字段可以为NULL 注意 ...

  7. epoll使用详解:epoll_create、epoll_ctl、epoll_wait、close

    epoll - I/O event notification facility 在linux的网络编程中,很长的时间都在使用select来做事件触发.在linux新的内核中,有了一种替换它的机制,就是 ...

  8. c++最大公约数

    C++辗转相除法求出最大公因数 样例输入 6 9 样例输出 3 程序 #include <stdio.h> using namespace std; int gcd(int m,int n ...

  9. 利用jenkins实现自动构建、部署,提升团队开发效率

    一大早就被群里的同学刷银川下雪的消息,看着我都发冷,突觉一阵凉风裹身,是不是该考虑秋裤了. 偏离主题,正文走起...... 使用jenkins目标:利用其结合maven完成自动构建,并部署到tomca ...

  10. Hash的应用

    思路:此题比较简单,直接贴代码 #include <stdio.h> int main(){ int N; ){ ]={}; ;i<N;i++){ int x; scanf(&quo ...