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 ...
随机推荐
- 【线性代数】6-3:微分方程的应用(Applications to Differential Equations)
title: [线性代数]6-3:微分方程的应用(Applications to Differential Equations) categories: Mathematic Linear Algeb ...
- Android Jenkins 自动化打包构建
前言 在测试app项目过程中,通常都是需要开发打测试包给到测试,但是无论是iOS还是Android的打包过程都是相当漫长的,频繁的回归测试需要频繁的打包,对于开发同学影响还是蛮大的.因此在这种情况下, ...
- Fltiss项目的架构、包名的定义和类的划分
这是项目的一览 首先Web根目录. 除了WEB-INF以外,还有css,img,js,lib目录,这四者都是静态资源. 由于客户端无法访问WEB-INF下的内容,所以将它们放置在了Web根目录下. 而 ...
- JAVA基础知识|类设计技巧
1.一定要保证数据私有 2.一定要对数据初始化 3.不要再类中使用过多的基本类型 4.不是所有的域都需要独立的域访问器和域更改器 5.将职责过多的类进行分解 6.类名和方法名要能够体现它们的职责 7. ...
- Java并发指南11:解读 Java 阻塞队列 BlockingQueue
解读 Java 并发队列 BlockingQueue 转自:https://javadoop.com/post/java-concurrent-queue 最近得空,想写篇文章好好说说 java 线程 ...
- Linux设备驱动程序 之 get_free_page
get_free_page 如果模块需要分配大块的内存,使用面向页的分配会有很多优点: 分配页面可使用下面的函数: unsigned long get_zeroed_page(gfp_t gfp_ma ...
- Flutter点击两次返回键退出APP
在APP中一些页面为了防止用户操作失误点击到返回键导致退出APP,可以设置其一定时间内点击两次返回键才允许退出APP,完成这个功能可以通过WillPopScope和SystemNavigator.po ...
- The problem is now the wait_for_fds() example function: it will call something like select(), poll() or the more modern epoll() and kqueue().
小结: 1.线程与惊群效应 Serializing accept(), AKA Thundering Herd, AKA the Zeeg Problem — uWSGI 2.0 documentat ...
- Dart 语法中文在线学习网址收藏
为了学习flutter UI框架,必须先学好dart语言,故收藏了有关 Dart 语法中文在线学习网址 http://dart.goodev.org/guides/language/language- ...
- JAVA运维总结篇
写这篇文章主要目的是完成自己多年来运维JAVA应用的一个总结,相当于个人知识库,以后工作中遇到问题便于临时查阅并不断完善自己的知识体系. 上图,就知道Tomcat在JAVA容器界是多么重要. ...