归并排序,在实际开发中,很少用,但是为什么一定要掌握它,甚至在面试中经常会问到。
其实,只是为了更好的理解算法。归并排序最核心的就是分治策略,所谓分治,就是把一个问题,拆分成若干个小问题然后求解。掌握归并排序以后,在遇到更复杂的问题,我们可以考虑分治策略。
归并排序是稳定的,时间复杂度是O(nlogn),空间复杂度是O(n)。
废话少说了,以下是我画的丑陋的分治图,凑合看吧。
以下是c代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
*@func:合并被middle分割的两个数组,以下称为左右两部分
*@input:data数组,start开始位置,middle中间位置,end结束位置
*@output:void
*/
void merger(int *data,int start,int middle,int end){
int i = start;//左边开始位置
int j = middle+1;//右边开始位置
int len = end-start+1;
//动态申请内存,毕竟int temp[len] 的方式可能会栈内存不足
int *temp = (int *)malloc(sizeof(int)*len);
if(temp == NULL)
return ;
int k = 0;
//开始合并,这里是升序
while(i <= middle && j <= end){
if(data[i] < data[j]){
temp[k++] = data[i++];
}else{
temp[k++] = data[j++];
}
}
//检查左边部分是否合并完
while(i <= middle){
temp[k++] = data[i++];
}
//检测右边部分是否合并完
while(j <= end){
temp[k++] = data[j++];
}
//把有序的temp数组中的数据复制到我们要的data数组中
memcpy(&data[start],temp,sizeof(int)*len);
free(temp);
}
void mergerSort(int *data,int start,int end){
int middle = start + (end - start)/2;
//使用递归,分治法,先分若干小组,然后再合并成大的有序数组
if(start < end){
mergerSort(data, start,middle);//左边部分
mergerSort(data, middle+1, end);//右边部分
merger(data, start, middle, end);//合并左右两部分数据
}
}
void call_merger_sort(int *data,int size){
if(data == 0 || size <=0)
return ;
mergerSort(data,0,size-1);
}
void show_numbers(int *data,int size){
int i = 0;
for(;i < size;++i){
printf("%d ",data[i]);
}
printf("\n");
}
//test...
int main(void ){
int data[]={9,2,5,1,3,8,7,6,4,0,999,21,567,23,88,1000,301,100};
int size = sizeof(data)/sizeof(data[0]);
printf("start sort:\n");
show_numbers(data,size);
sort(data, size);
printf("end sort:\n");
show_numbers(data, size);
}
输出结果: