C++版 归并排序
在原作者基础上加入注释
原作者: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++版 归并排序的更多相关文章
- javascript实现非递归--归并排序
另一道面试题是实现归并排序,当然,本人很不喜欢递归法,因为递归一般都是没有迭代法好.所以首选都是用迭代法,但是迭代法确实是难做啊,至底而上的思想不好把握. 这是我的实现代码 /* * * 非递归版归并 ...
- 算法与数据结构(十五) 归并排序(Swift 3.0版)
上篇博客我们主要聊了堆排序的相关内容,本篇博客,我们就来聊一下归并排序的相关内容.归并排序主要用了分治法的思想,在归并排序中,将我们需要排序的数组进行拆分,将其拆分的足够小.当拆分的数组中只有一个元素 ...
- 算法导论(第三版)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 ...
- 归并排序—Java版
一开始做算法的时候,感觉递归算法很绕,所以我就在阅读别人代码的基础上,对代码每一步都添加自己的注解,方便我以后的学习. public class MergeSort { /** * 归并排序 * @p ...
- C#版 - LeetCode 148. Sort List 解题报告(归并排序小结)
leetcode 148. Sort List 提交网址: https://leetcode.com/problems/sort-list/ Total Accepted: 68702 Total ...
- 结合《剑指offer(第二版)》面试题51来谈谈归并排序
一.题目大意 给定一个数组A,对于数组A中的两个数字,如果排在前面的一个数字大于(必须大于,等于不算)后面的数字,则这两个数字组成一个逆序对.要求输出数组A中的逆序对的总数.例如,对于数组{7,5,6 ...
- 算法分析中最常用的几种排序算法(插入排序、希尔排序、冒泡排序、选择排序、快速排序,归并排序)C 语言版
每次开始动手写算法,都是先把插入排序,冒泡排序写一遍,十次有九次是重复的,所以这次下定决心,将所有常规的排序算法写了一遍,以便日后熟悉. 以下代码总用一个main函数和一个自定义的CommonFunc ...
- 数据结构之排序技术:快速排序、归并排序、堆排序(C++版)
快速排序 #include <iostream> using namespace std; void swap(int num[], int i, int j) { int temp = ...
- C++_归并排序(纯C版)
#include <iostream> #include <stdlib.h> using namespace std; int compared(const void *ke ...
随机推荐
- Java面向对象2(G~J)
G 织女的红线(SDUT 2240) import java.util.Scanner; import java.text.DecimalFormat; class Sum { double x ...
- Linux中查看和修改分区的uuid方便挂载使用
查看硬盘UUID: 两种方法: ls -l /dev/disk/by-uuid blkid /dev/sda1 修改分区UUID: 1.修改分区的UUID Ubuntu 使用 uuid命令 生成新的u ...
- Servlet页面跳转的两种方式
一.页面跳转 1. 请求转发: (1) 使用requestDispatcher对象: 转发格式:request.getRequestDispatcher("path").forwa ...
- linux安装puppeteer
1.安装 下载淘宝镜像的,可以同时下载puppeteer和chromium下面两条语句即可 npm install -g cnpm --registry=https://registry.npm.ta ...
- IDEA 重复代码快速重构(抽取重复代码快捷键)
Ctrl+Alt+M 顺带一提,eclipse的快捷键是:Alt+Shift+M;
- 错误Uncaught Error: Bootstrap's JavaScript requires jQuery at bootstrap.min.js:6 错误详解
引入Bootstrap的顺序进行修改 <% //获取以/开始,不以/结尾的部分 pageContext.setAttribute("APP_PATH", request.ge ...
- 记录linux 生成crash dump文件步骤
执行文件编译时加入-g 命令 例如 g++ -g test.cpp 查看当前系统限制情况 ulimit -a 设置crash dump 文件大小 ulimit -c unlimited unlimit ...
- Java同步数据结构之DelayQueue/DelayedWorkQueue
前言 前面介绍了优先级队列PriorityBlockingQueue,顺带也说了一下PriorityQueue,两者的实现方式是一模一样的,都是采用基于数组的平衡二叉堆实现,不论入队的顺序怎么样,ta ...
- java静态标示符static详解
1.static修饰的变量习惯称为静态变量,static修饰的方法称为静态方法,static修饰的代码块叫做静态代码块. 1)static变量 static变量也称作静态变量,静态变量和非静态变量的区 ...
- js和微信小程序本地获取东八北京时间
changeCount(){ // 目标时区,东8区 const targetTimezone = -8; // 当前时区与中时区时差,以min为维度 const dif = new Date().g ...