将n个数分成n/2组,排序好,再两两合并,分成n/4组,再依次上去,因为已经排序好了,合并起来很快。
每次需要对比的次数为n次
比如n=64时
当n/4时,每队有4个数,总共有16组,第一队的4个数与第二队的4个数对比,需要最多8次。总共有8组(每组2对)需要对比,即对比64次,也就是n
即分解后都需要对比n次,那需要分解多少次呢?
64/2, 64/2/2, 64/2/2/2
就是需要分解log2^n次,64可以分解6次,2,4,8,16,32,64
所以归并排序的复杂度为O(nlgn),算法中log2#n(2为底)直接写成lgn即可,底数一般不考虑,因为n很大时,底数已经不是英雄数目的关键了
归并排序还有个好处,可以多线程分开执行,效率更高。
有点像平时打牌,左边一堆已经排好序的,右边已经排好序列,这两堆要排序,只需要依次比较他们最小的值,最多比较n次就结束了。好的情况,第一堆比较完了,第二堆很快与"空"比较。
int sort_merge(int* ptr_data, int start_index, int mid_index, int stop_index)
{
int n1 = mid_index - start_index + 1; //
int n2 = stop_index - mid_index;
int* ptr_data1 = (int*)malloc(sizeof(int) * (n1 + 1));
int* ptr_data2 = (int*)malloc(sizeof(int) * (n2 + 1));
int i = 0;
for(i = 0; i < n1; ++i)
{
ptr_data1[i] = ptr_data[i + start_index];
}
ptr_data1[n1] = 65535; // 设置一个最大的“空"值,这样ptr_data2对比起来肯定比它小
for(i = 0; i < n2; ++i)
{
ptr_data2[i] = ptr_data[i + mid_index + 1];
}
ptr_data2[n2] = 65535;
int data1_index = 0;
int data2_index = 0;
for(i = start_index; i < stop_index; ++i)
{
if (data1_index > n1 || data2_index > n2)
{
assert(0);
}
if (ptr_data1[data1_index] > ptr_data2[data2_index])
{
ptr_data[i] = ptr_data2[data2_index];
++data2_index;
}
else
{
ptr_data[i] = ptr_data1[data1_index];
++data1_index;
}
}
}