1、思想:多次将两个或两个以上的有序表合并成一个新的有序表。
2、算法时间复杂度
最好的情况下:一趟归并需要n次,总共需要logN次,因此为O(N*logN)
最坏的情况下,接近于平均情况下,为O(N*logN)
说明:对长度为n的文件,需进行logN 趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)。
3、稳定性
归并排序最大的特色就是它是一种稳定的排序算法。归并过程中是不会改变元素的相对位置的。
4、缺点是,它需要O(n)的额外空间。但是很适合于多链表排序。
排好序的序列。貌似这个跟排序关系不大,因为排序给的是一个乱的序列,而合并是合并的两个已经排序
好的序列。且慢,我们可以把需要排序的数据分解成N个子序列,当分解的子序列所包含数据个数为1的时
候,那么这个序列不久是有序了吗?然后再合并。这个就是有名的”分治“了。例如321分成3,2,1三个序
列,1这个序列是有序的啦。。同理2,3都是有序的。然后我们逐一的合并他们。3,2合并为23,然后在
23与1合并为123。哈哈,排序成功。合并排序主要思路就是这样了。但是,问题又出来了,怎么合并两
个有序列呢?我相信我应该理解了数组的存储方式,所以直接用数组说事啦。。我们先把下标定位到各有
序子序列的开始,也把合并之后数组的下标定位到最初。那么下标对应的位置就是他们当前的最小值了。
然后拿他们来比较,把更小的那个放到合并之后数组的下标位置。这样,合并后数组的第一个元素就是他
们的最小值了。接着,控制合并后数组的下标后移一个,把比较时小数字所在序列对应的下标后移一个。
这样。下次比较的时候,他得到就是他的第二小,(第一下已经合并了)就是当前最小值了,在于另一
个序列的当前最小值比较,用小的一个放到合并后数组的相应位置。依次类推。接着当数据都合并玩了结
束,合并完成。
来做例子:
(1回合) 1357 2468 (合并后数据空)
(2) 357 2468 100000(0表示空) 因为1 < 2所以把1放到合并后位置中了(这里1并不是丢掉了,而是下
标变为指向3了,1是没有写而已。呵呵。理解为数组的下标指向了3)
(3) 357 468 120000 因为3 > 2,所以把而放进去
(4) 57 468 123000 同理3 < 4
(5) 57 68 1234000 同理5 > 4
(6) 7 68 1234500 同理5 > 6
(7) 7 8 1234560 同理7 > 6
(8) 0(空了) 8 12345670 同理7 < 8
(9) 0 0 12345678 弄最后一个
当然,这些只是思路。并不是一定一成不变的这样。合并OK,那么我们就可以用合并排序了哦!哈哈。。
不过注意,那个321全部弄成一个单个数字,然后一个一个合并这样来合并似乎不是很好,貌似还有更好
的解决方案。哈哈,对了,就是我先分一半来合并。如果这一半是排好序的,那么合并不久简单了吗?但
是我怎么让一般排好序呢。呵呵简单,我一半在分一半合并排序,在分一半合并排序,直到分到两个都是
1个了,就合并,ok!
例如,81726354:
(1)分成9172 6354
(2)把8172 分成 81 和72 把6354分成63和54
(3)81分成8和1,哦能合并了哦。合并为18, 同理72,63,54,也可以分解成单个合并为27,36,45
(4) 现在变为了 18, 27, 36, 45了,这个时侯,18 和27能合并了,合并为1278 同理36,合并为45 3456
(5) 好了最好吧,1278和3456合并为12345678.ok排序成功。哈哈。
这样把一个问题分解为两个或多个小问题,然后在分解,最后解决小小问题,已达到解决大问题的目的。
思路主要就是这样了哦:
程序实现上也有点技巧。这个就不说了,直接奉上源代码:
#define INFINITE 1000 //对两个序列进行合并,数组从mid分开 //对a[start...mid]和a[mid+1...end]进行合并 void merge(int *a,int start,int mid,int end) { int i,j,k; //申请辅助数组 int *array1=(int *)malloc(sizeof(int)*(mid-start+2)); int *array2=(int *)malloc(sizeof(int)*(end-mid+1)); //把a从mid分开分别赋值给数组 for(i=0;i<mid-start+1;i++) *(array1+i)=a[start+i]; *(array1+i)=INFINITE;//作为哨兵 for(i=0;i<end-mid;i++) *(array2+i)=a[mid+1+i]; *(array2+i)=INFINITE; //有序的归并到数组a中 i=j=0; for(k=start;k<=end;k++) { if(*(array1+i) > *(array2+j)) //如果不设置哨兵,那么因为start到end的区间远大于array的大小,所以,当array的数组下表分配完时,会产生数组越界! { a[k]=*(array2+j); j++; } else { a[k]=*(array1+i); i++; } } free(array1); free(array2); } //归并排序 void mergeSort(int *a,int start,int end) { int mid=(start+end)/2; if(start<end){ //分解 mergeSort(a,start,mid); //1 mergeSort(a,mid+1,end); //2 //合并 merge(a,start,mid,end); //30 } }