目录
2. 和选择排序,冒泡排序等的暴力排序的区别在哪里,为什么快?
了解其他常用算法点这里 >> https://blog.csdn.net/GD_ONE/article/details/104061907
归并排序是分治法思想的实例,学习完归并排序后会更加理解分治法思想和递归思想。
- 什么是归并排序?
- 和选择排序,冒泡排序的区别在哪里,为什么它要比以上两种排序快呢?
- 我们要怎么实现归并排序?
本文将主要解决以上三个问题。
1.什么是归并排序?
归并排序的主要思想是:
1). 归0
将无序的数列分为两个部分,对于每个部分,在继续划分为更小的两部分,直到每个部分都有序,即分解为单个数据,因为仅有一个数一定是有序的。
2). 合并
把每次分开的两部分再合并到一起。合并是归并排序的核心。
2. 和选择排序,冒泡排序等的暴力排序的区别在哪里,为什么快?
选择排序和冒泡排序直接对原数列进行遍历比较,要比较n+(n-1)+(n-2)...+1次,时间复杂度为o(n^2)
归并排序采用了分治法思想,将待排序的数列分解为两个更小的数列,分解数列的时间复杂度为o(log2n),每一次分解都需要将两个有序的数列合并在一起,合并两个有序数列的时间复杂度是o(n)所以总的时间复杂度是 o(nlog2n)。
3. 代码实现归并排序
先看下图, 图来自https://www.cnblogs.com/onepixel/p/7674659.html
首先解决分的问题,需要将数列分为两个部分, 在将每个部分再次分为两个部分,直到不可再分。
我们可以使用递归的方式来实现归并排序,其实分治法的思想几乎就是递归的过程。
对于每一个序列,每次都按左右两部分划分,所以 int mid = l+r>>1;
然后对 (l, mid) 和 (mid + 1, r) 两部分再次递归划分。当l == r 时不再继续划分。
( 另: l+r >>1 是位运算, 相当于 (l+r)/ 2 )
代码:
int mergesort(int a[], int l, int r){
if(l==r) return;
int mid = l+r>>1;
mergesort(a, l, mid);
mergesort(a, mid+1, r);
}
分完之后就剩下合并了
上面说到 将两个有序的序列合并为一个, 那么怎么合并呢, 首先我们当然需要一个额外的数组去存储这个合并后的序列,
然后比较将两个有序的序列的每一个数据,按照大小关系将数据存入额外数组。
如 1 3 5 和 2 4 6
先比较1 2 1 < 2 将1存入, 然后比较2 3 2 < 3 将2存入 以此类推。
完整代码:
void mergesort(int a[], int l, int r){
if(l>=r) return;
int mid = l+r>>1;
mergesort(a, l, mid);
mergesort(a, mid+1, r);
int i,j,k = l;
for(i = l, j = mid + 1; i <= mid&&j <= r;){
if(a[i] > a[j]){
b[k++] = a[j];
j++;
}
else b[k++] = a[i], i++;
}
while(i <= mid) b[k++] = a[i++];
while(j <= r) b[k++] = a[j++];
for(int ii = l; ii <= r; ii++){
a[ii] = b[ii];
}
}