归并排序
简介:
前面介绍的插入排序,交换排序和选择排序这三类排序算法都是将无序的记录序列按关键字的大小排成一个有序序列.
而归并排序则是将两个或两个以上的有序序列合并成一个有序序列的过程.
归并排序(Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法,效率为O(n log n)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。
算法描述:
首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。
- eg:
1
2
3
4
5
6
7
8a: 1 3 5 7 9
b: 2 4 6 8 10 12 14
//1 和 2, 比, 小,将 1 放入c,
//3 和 2, 比, 大,将 2 放入c,
//3 和 4, 比, 小,将 3 放入c,
....
c > 1 2 3 4 5 6 7 8 9 10 12 14
//我们在合并这两个序列时,每次只用比较当前a序列第一个和当前b序列第一个的大小,谁小就先放入有序序列中,当a比较完后,直接将b剩余的依次放入有序序列即可.
1 |
|
//可以看出合并有序数列的效率是比较高的,可以达到O(n)。
//解决了上面的合并有序数列问题,再来看归并排序,其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了?
//可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递[归]的分解数列,再合[并]数列就完成了[归并]排序。
过程演示:
1 |
|
算法思想:
归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。
- 迭代法
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针到达序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
- 递归法
原理如下(假设序列共有n个元素):
- 将序列每相邻两个数字进行归并操作,形成
floor(n/2)
个序列,排序后每个序列包含两个元素 - 将上述序列再次归并,形成
floor(n/4)
个序列,每个序列包含四个元素 - 重复步骤2,直到所有元素排序完毕
程序代码:
按照此定义,我们很容易写出归并排序的程序代码:
1 |
|
功能检测
- 检测代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16int main()
{
int i =0;
int a[] = {3,0,1,8,7,2,5,4,6,9};
int n = sizeof(a)/sizeof(a[0]);
Merge(a, n);
printf("\n");
for(i = 0; i < n ; ++i)
{
printf("%3d",a[i]);
}
printf("\n");
return 0;
} - 运行结果:
1 |
|
总结:
归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(NlogN)。
因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(NlogN)的几种排序方法(快速排序,归并排序,希尔排序)也是效率比较高的。