时间复杂度为O(nlog2n),这是算法中最坏和平均的时间性能最好的一种,空间复杂度为O(n).
缺点就是比较占用内存,但却是一种效率高且稳定的算法(速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对
有序的数列)。
所谓归并排序是指两个或者两个以上有序的数列,合并成一个仍然有序的数列,这种排序经常用于多个有序的数据文件归并成一个有序的数
据文件。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和
右区间用一次归并操作合并成有序的区间[s,t]。
作了解:
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11,;
逆序数为14;
言归正传,首先考虑下如何将将二个有序数列合并(先用二路归并实现)。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。
我用java实现合并,然后顺便使用set去除相同元素,注意点:初始化易错,int a[] = new int[10]; Set<Integer> s = new HashSet<Integer>();其他的看代码注意;
public static void main(String[] args) {
int a[] = { 1, 3, 4, 5, 7 };
int b[] = { 2, 3, 6, 8, 9 };
int c[] = new int[10];// 初始化空间大小很重要
int i, j, k;
i = j = k = 0;
int n = a.length;
int m = b.length;
while (i < n && j < m) {
if (a[i] < b[j]) {
c[k++] = a[i++];
} else {
c[k++] = b[j++];
}
}
while (i < n) {
c[k++] = a[i++];
}
while (j < m) {
c[k++] = b[j++];
}
// Set是一个接口,不能直接实例化,HashSet实现了Set接口,所以可以new HashSet()
Set<Integer> s = new HashSet<Integer>();
for (int aa = 0; aa < c.length; aa++) {
s.add(c[aa]);
System.out.print(c[aa] + ",");
}
System.out.println();
int aa = 0;// 用while循环实现上面的方法
while (aa < c.length) {
s.add(c[aa++]);
}
Iterator<Integer> it = s.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
c语言实现:
void mArray(int a[],int n,int b[],int m,int c[]){
int i,j,k;
i=j=k=0;
while(i<n && j<m){
if(a[i] < b[j])
c[k++]=a[i++];
else
c[k++]=b[j++];
}
while(i<n){
c[k++]=a[i++];
}
while(j<m){
c[k++]=b[j++];
}
}
以下转自MoreWindows文章。
可以看出合并有序数列的效率是比较高的,可以达到O(n)。
解决了上面的合并有序数列问题,再来看归并排序,其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了?
可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。
- //将有二个有序数列a[first...mid]和a[mid...last]合并。 自己调试有错误,下面是自己找的作法
- void mergearray(int a[], int first, int mid, int last, int temp[])
- {
- int i = first, j = mid+1 ;
- int m = mid, n = last;
- int k = 0;
- while (i <= m && j <= n)
- {
- if (a[i] <= a[j])
- temp[k++] = a[i++];
- else
- temp[k++] = a[j++];
- }
- while (i < m)
- temp[k++] = a[i++];
- while (j < n)
- temp[k++] = a[j++];
- for (i = 0; i < k; i++)
- a[first + i] = temp[i];
- }
- void mergesort(int a[], int first, int last, int temp[])
- {
- if (first < last)
- {
- int mid = (first + last) / 2;
- mergesort(a, first, mid, temp); //左边有序
- mergesort(a, mid + 1, last, temp); //右边有序
- mergearray(a, first, mid, last, temp); //再将二个有序数列合并
- }
- }
- bool MergeSort(int a[], int n)
- {
- int *p = new int[n];
- if (p == NULL)
- return false;
- mergesort(a, 0, n - 1, p);
- delete[] p;
- return true;
- }
归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。
在本人电脑上对冒泡排序,直接插入排序,归并排序及直接使用系统的qsort()进行比较(均在Release版本下)
对20000个随机数据进行测试:
对50000个随机数据进行测试:
再对200000个随机数据进行测试:
注:有的书上是在mergearray()合并有序数列时分配临时数组,但是过多的new操作会非常费时。因此作了下小小的变化。只在MergeSort()中new一个临时数组。后面的操作都共用这一个临时数组。
最后附上自己的java实现归并的代码:
public static void main(String[] args) {
// int a[] = { 6, 4, 7, 5, 8 };
int a[] = { 25, 10, 7, 19, 3, 48, 12, 17, 56, 30, 21 };
int p[] = new int[a.length + 1];
doMerge(a, 0, a.length, p);
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + "--");
}
}
public static void doMerge(int[] a, int frist, int last, int[] p) {
if (frist + 1 < last) {
int mid = (frist + last) / 2;
doMerge(a, frist, mid, p);
doMerge(a, mid, last, p);
mergeArray(a, frist, mid, last, p);
}
}
public static void mergeArray(int a[], int frist, int mid, int last,
int p[]) {
int i = frist, j = mid;
int m = mid, n = last;
int k = 0;
while (i < m && j < n) {
if (a[i] <= a[j]) {
p[k++] = a[i++];
} else {
p[k++] = a[j++];
}
}
while (j < n) {
p[k++] = a[j++];
}
while (i < m) {
p[k++] = a[i++];
}
for (i = 0; i < k; i++) {
a[frist + i] = p[i];
}
}
相关学习链接:http://www.cnblogs.com/jillzhang/archive/2007/09/16/894936.html
http://blog.csdn.net/morewindows/article/details/6678165