排序(二):归并排序

归并排序是分治法思想的实例,学习完归并排序后会更加理解分治法思想和递归思想。

  1. 什么是归并排序?
  2. 和选择排序,冒泡排序的区别在哪里,为什么它要比以上两种排序快呢?
  3. 我们要怎么实现归并排序?

本文将主要解决以上三个问题。

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];
	}
}
发布了52 篇原创文章 · 获赞 114 · 访问量 5997

猜你喜欢

转载自blog.csdn.net/GD_ONE/article/details/103842134