在原作者基础上加入注释

原作者:https://www.cnblogs.com/agui521/p/6918229.html

归并排序:归并排序(英语:Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法,效率为O(n log n)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。

归并排序的核心思想是将两个有序的数列合并成一个大的有序的序列。通过递归,层层合并,即为归并。

如图,从下到上,每一步都需要将两个已经有序的子数组合并成一个大的有序数组,如下是实现合并的具体代码,请读者细细体会

 
void merge(int arr[],int l,int mid,int r)
{
int aux[r-l+1];//开辟一个新的数组,将原数组映射进去
for(int m=l;m<=r;m++)
{
aux[m-l]=arr[m];
} int i=l,j=mid+1;//i和j分别指向两个子数组开头部分 for(int k=l;k<=r;k++)
{           
  //分四种情况判断:
  //i>mid 把大于mid的数据并入;j>r 把i-mid的数据并入;
//aux[i-l]<aux[j-l],把小的数据即aux[i-l]并入,同理aux[i-l]>=aux[j-l]
if(i>mid)
{
arr[k]=aux[j-l];
j++;
}
else if(j>r)
{
arr[k]=aux[i-l];
i++;
}
else if(aux[i-l]<aux[j-l])
{
arr[k]=aux[i-l];
i++;
}
else
{
arr[k]=aux[j-l];
j++;
}
}
}

  

 

上图代码已经完成了归并中的“并”这一部分,归并归并,有并必有归,如下实现“归”的部分

1 void merge_sort(int arr[],int l,int r)
2 {
3 if(l >=r)
4 return ;
5 int mid=(l+r)/2;
6 merge_sort(arr,l,mid);  //这个函数的递归为了获取 l和mid 的值
7 merge_sort(arr,mid+1,r); //这两个递归主要为了获取 r 的值 为下面的 merge函数提供实参
8 merge(arr,l,mid,r);    
9 }

由于上图中的l,r不方便使用者调用,于是我们创建一个方便自己调用的my_merge_sort函数

1 void my_merge_sort(int arr[],int n)
2 {
3 merge_sort(arr,0,n-1);
4 }

以上我们便实现了归并排序中的归和并,归并排序是利用二分法实现的排序算法,时间复杂度为nlogn,是一种比较快速的排序算法。如下是笔者自己写的归并排序的全部代码,

 1 #include <iostream>
2 using namespace std;
3
4
5 void merge(int arr[],int l,int mid,int r)
6 {
7 int aux[r-l+1];//开辟一个新的数组,将原数组映射进去
8 for(int m=l;m<=r;m++)
9 {
10 aux[m-l]=arr[m];
11 }
12
13 int i=l,j=mid+1;//i和j分别指向两个子数组开头部分
14
15 for(int k=l;k<=r;k++)
16 {
17 if(i>mid)
18 {
19 arr[k]=aux[j-l];
20 j++;
21 }
22 else if(j>r)
23 {
24 arr[k]=aux[i-l];
25 i++;
26 }
27 else if(aux[i-l]<aux[j-l])
28 {
29 arr[k]=aux[i-l];
30 i++;
31 }
32 else
33 {
34 arr[k]=aux[j-l];
35 j++;
36 }
37 }
38 }
39 //递归的使用归并排序,对arr[l....r]排序
40 void merge_sort(int arr[],int l,int r)
41 {
42 if(l >=r)
43 return ;
44 int mid=(l+r)/2;
45 merge_sort(arr,l,mid);
46 merge_sort(arr,mid+1,r);
47 merge(arr,l,mid,r);
48 }
49
50 void my_merge_sort(int arr[],int n)
51 {
52 merge_sort(arr,0,n-1);
53 }
54
55 int main()
56 {
57 int a[6];
58 for(int i=0;i<6;i++)
59 {
60 cin>>a[i];
61 }
62 my_merge_sort(a,6);
63 for(int i=0;i<6;i++)
64 {
65 cout<<a[i]<<" ";
66 }
67 return 0;
68 }

上面实现的归并排序是自顶向下的,我们可以以另外一种方向来实现归并,改递归为迭代。如下实现

1 #include <iostream>
2 #include <math.h>
3 using namespace std;
4
5 void merge(int arr[],int l,int mid,int r)
6 {
7 int aux[r-l+1];//开辟一个新的数组,将原数组映射进去
8 for(int m=l;m<=r;m++)
9 {
10 aux[m-l]=arr[m];
11 }
12
13 int i=l,j=mid+1;//i和j分别指向两个子数组开头部分
14
15 for(int k=l;k<=r;k++)
16 {
17 if(i>mid)
18 {
19 arr[k]=aux[j-l];
20 j++;
21 }
22 else if(j>r)
23 {
24 arr[k]=aux[i-l];
25 i++;
26 }
27 else if(aux[i-l]<aux[j-l])
28 {
29 arr[k]=aux[i-l];
30 i++;
31 }
32 else
33 {
34 arr[k]=aux[j-l];
35 j++;
36 }
37 }
38 }
39
40 void mergesort(int arr[],int n)
41 {
42 for(int sz=1;sz<=n;sz+=sz)
43 {
44 for(int i=0;i+sz<n;i+=sz+sz)//i+sz防止越界 i+=sz+sz 相当于 i+=(sz+sz) 先2个2个排序,再4个4个排序,再8个8个排序 45       {//对arr[i...sz-1]和arr[i+sz.....i+2*sz-1]进行排序
46       merge(arr,i,i+sz-1,min(i+sz+sz-1,n-1)); //min函数防止越界 
47       } 
48   }
49
50 }
51
52 int main()
53 {
54 int a[5];
55 for(int i=0;i<5;i++)
56 {
57 cin>>a[i];
58 }
59 mergesort(a,5);
60 for(int i=0;i<5;i++)
61 {
62 cout<<a[i]<<" ";
63 }
64 return 0;
65 }

C++版 归并排序的更多相关文章

  1. javascript实现非递归--归并排序

    另一道面试题是实现归并排序,当然,本人很不喜欢递归法,因为递归一般都是没有迭代法好.所以首选都是用迭代法,但是迭代法确实是难做啊,至底而上的思想不好把握. 这是我的实现代码 /* * * 非递归版归并 ...

  2. 算法与数据结构(十五) 归并排序(Swift 3.0版)

    上篇博客我们主要聊了堆排序的相关内容,本篇博客,我们就来聊一下归并排序的相关内容.归并排序主要用了分治法的思想,在归并排序中,将我们需要排序的数组进行拆分,将其拆分的足够小.当拆分的数组中只有一个元素 ...

  3. 算法导论(第三版)Exercises2.3(归并排序、二分查找、计算集合中是否有和为X的2个元素)

    2.3-1: 3 9 26 38 41 49 52 59 3 26 41 52   9 38 49 57 3 41   52 26   38 57   9 49 3   41  52  26  38  ...

  4. 归并排序—Java版

    一开始做算法的时候,感觉递归算法很绕,所以我就在阅读别人代码的基础上,对代码每一步都添加自己的注解,方便我以后的学习. public class MergeSort { /** * 归并排序 * @p ...

  5. C#版 - LeetCode 148. Sort List 解题报告(归并排序小结)

    leetcode 148. Sort List 提交网址: https://leetcode.com/problems/sort-list/  Total Accepted: 68702 Total ...

  6. 结合《剑指offer(第二版)》面试题51来谈谈归并排序

    一.题目大意 给定一个数组A,对于数组A中的两个数字,如果排在前面的一个数字大于(必须大于,等于不算)后面的数字,则这两个数字组成一个逆序对.要求输出数组A中的逆序对的总数.例如,对于数组{7,5,6 ...

  7. 算法分析中最常用的几种排序算法(插入排序、希尔排序、冒泡排序、选择排序、快速排序,归并排序)C 语言版

    每次开始动手写算法,都是先把插入排序,冒泡排序写一遍,十次有九次是重复的,所以这次下定决心,将所有常规的排序算法写了一遍,以便日后熟悉. 以下代码总用一个main函数和一个自定义的CommonFunc ...

  8. 数据结构之排序技术:快速排序、归并排序、堆排序(C++版)

    快速排序 #include <iostream> using namespace std; void swap(int num[], int i, int j) { int temp = ...

  9. C++_归并排序(纯C版)

    #include <iostream> #include <stdlib.h> using namespace std; int compared(const void *ke ...

随机推荐

  1. Appium获取toast消息

    Android获取toast,需要在参数里设置automationName:Uiautomator2 设置设备的信息 desired_caps = { 'platformName': 'Android ...

  2. GoEasy实现websocket 推送消息通知到客户端

    最近在实现一个推送功能,用户扫描二维码签到,后台及时将签到成功信息推送到浏览器端.排除了前端ajax轮询的方式,决定采用websocket及时推送. 于是发现了第三方websocket推送库GoEas ...

  3. AcWing:241. 楼兰图腾(树状数组逆序对)

    在完成了分配任务之后,西部314来到了楼兰古城的西部. 相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(‘V’),一个部落崇拜铁锹(‘∧’),他们分别用V和∧的形状来代表各自 ...

  4. Ubuntu常用命令及git常用命令

    1. CMakeLists.txt中指定OpenCV路径 set(OPENCV_DIR /***/***/opencv-2.4.9) 2. cmake工程编译安装 mkdir build cd bui ...

  5. 卸载Ambari集群

    清理ambari安装的hadoop集群 本文针对redhat或者centos 对于测试集群,如果通过ambari安装hadoop集群后,想重新再来一次的话,需要清理集群. 对于安装了很多hadoop组 ...

  6. 在SQLAlchemy ORM中动态变更表名

    在开发过程中,经常会遇到几张表结构相同,仅仅表名不一样.这在直接使用SQL语句进行查询的环境中处理起来很简单,但如果使用了SQLAlchemy ORM之后,因在model定义时就确定了表名,就需要用其 ...

  7. TypeError: Data location must be "memory" for return parameter in function, but none was given.

      在用truffle编译智能合约时,报错 TypeError: Data location must be "memory" for return parameter in fu ...

  8. Razor字符串处理

    需要注意的是低版本是不支持C# 6语法中的string interpolation的 <label> @if (!string.IsNullOrEmpty(Model.BudgetValu ...

  9. Vue开发工具VS Code与调试

    vscode安装 进入vscode官网(https://code.visualstudio.com/Download)vscode插件安装进入vscode官网插件商店(https://marketpl ...

  10. ELK的安全解决方案 X-Pack(1)

    安装 X-Pack 前必须安装 elasticsearch. Kibana.logstash,因为之前安装ELK选择的版本都是5.4.1,所以这次选择X-Pack的版本也要是5.4.1的 第一步:下载 ...