一、归并排序(Merge Sort)
归并排序是一个相当“稳定”的算法对于其它排序算法,比如希尔排序,快速排序和堆排序而言,这些算法有所谓的最好与最坏情况。而归并排序的时间复杂度是固定的,它是怎么做到的?
二、算法原理
首先来看归并排序要解决的第一个问题:两个有序的数组怎样合成一个新的有序数组,比如数组1{ 3,5,7,8 }、数组2为{ 1,4,9,10 },首先那肯定是创建一个长度为8的新数组咯,然后就是分别从左到右比较两个数组中哪一个值比较小,然后复制进新的数组中,比如我们这个例子:
{ 3,5,7,8 } { 1,4,9,10 }
{ }一开始新数组是空的。然后两个指针分别指向第一个元素,进行比较,显然,1比3小,所以把1复制进新数组中:
{ 3,5,7,8 } { 1,4,9,10 } { 1, }
第二个数组的指针后移,再进行比较,这次是3比较小:
{ 3,5,7,8 } { 1,4,9,10 } { 1,3, }
同理,我们一直比较到两个数组中有某一个先到末尾为止,在我们的例子中,第一个数组先用完。{ 3,5,7,8 } { 1,4,9,10 } { 1,3,4,5,7,8 }
最后把第二个数组中的元素复制进新数组即可。
{ 1,3,4,5,7,8,9,10 }
由于前提是这个两个数组都是有序的,所以这整个过程是很快的,我们可以看出,对于一对长度为N的数组,进行合并所需要的比较次数最多为2 * N -1。这其实就是归并排序的最主要想法和实现,归并排序的做法是:
将一个数组一直对半分,问题的规模就减小了,再重复进行这个过程,直到元素的个数为一个时,一个元素就相当于是排好顺序的。接下来就是合并的过程了,合并的过程如同前面的描述。一开始合成两个元素,然后合并4个,8个这样进行。所以可以看到,归并排序是“分治”算法的一个经典运用。
三、代码示例
/*合拼有序数组*/
int merge_array(int *array, int start, int middle, int end, int *temp)
{
int i, j, k = 0;
i = start;
j = middle + 1;
while(i <= middle && j <= end) {
if (array[i] <= array[j])
temp[k ++] = array[i ++];
else
temp[k ++] = array[j ++];
}
while (i <= middle)
temp[k ++] = array[i ++];
while (j <= end)
temp[k ++] = array[j ++];
for (i = 0; i < k; i ++)
array[start + i] = temp[i];
return 0;
}
/*将需要排序的数据递归对半拆分, 再进行合拼*/
int _merge_sort(int *array, int start, int end, int *temp)
{
int middle;
if (start < end) {
middle = (end + start) / 2;
_merge_sort(array, start, middle, temp);
_merge_sort(array, middle + 1, end, temp);
merge_array(array, start, middle, end, temp);
}
return 0;
}
int mergeSort(int *array, int length)
{
int *temp;
if (NULL == array || length <= 0)
return -1;
temp = (int *)malloc(sizeof(int) * length);
if (NULL == temp) {
perror("malloc error");
return -1;
}
memset(temp, 0, sizeof(int) * length);
_merge_sort(array, 0, length - 1, temp);
free(temp);
return 0;
}
四、实例测试
sort.c
int main(int argc, char **argv)
{
int i, length;
// int buf[5] = {
// 16, 32, 8, 12, 13
// };
int buf[] = {112, 5,1,11, 34, 10, 111,1234,44,33,23,56,77,88,43,41,2,4,19,13,3,8,6,0,9};
//int buf[10]={4,1,3,2,16,9,10,14,8,7};
length = sizeof(buf)/sizeof(int);
// heap_sort(buf-1, length);
// shell_sort(buf, length, 2);
// quick_sort(buf, 0, length - 1);
printf("start merge sort...\n\n");
mergeSort(buf, length);
for(i = 0; i < length; i++)
printf("%d\t ", buf[i]);
printf("\n");
return 0;
}
测试结果:
关注公众号"小败日记",搬砖过程遇到的问题,大家一起探讨,资源共享