归并排序的思想是将大数组细分成一个个小数组(甚至可以使小数组只包含一个元素),然后对小数组不断进行归并,从而得到排好序的大数组。
归并排序是基于比较的排序方式中的最优解,主要分为两种:自上而下和自底向上。两种排序方式的复杂度均为N*logN,较之初级排序方法的N^2大大提速,可以处理上百万个元素的数组,但是在解决小数组(元素数小于15)排序时,插入排序方法更快。
两种归并排序方法的区别主要在于自上而下的归并需要调用递归,而自底向上的归并排序不需要,因此自底向上的方法适合对链表进行排序操作。
以下为两种方式的代码:
void _merge(int *t, int lo, int mid, int hi) //将两个数组归并
{
const int N = sizeof(t) / sizeof(t[0]);
int tcpy[N];
for(int i = lo; i <= hi; i++) //将数组复制到辅助数组中
tcpy[i] = t[i];
int left = lo, right = mid+1; //左边数组标记和右边数组标记
for(int i = lo; i <= hi; i++) //向原数组中添加排列好的数据
{
if(left > mid) t[i] = tcpy[right++]; //左边数组已空,添加右边数组数据
else if(right > hi) t[i] = tcpy[left++]; //右边数组已空,添加左边数组数据
else if(tcpy[left] > tcpy[right]) t[i] = tcpy[right++]; //左边的大于右边的,添加右边
else t[i] = tcpy[left++]; //否则添加左边
}
}
void top_down_mergesort(int *t, int lo, int hi) //自上而下的归并排序(调用递归)
{
if(lo >= hi) //若子数组只剩一个元素,结束函数
return;
int mid = (lo+hi) / 2; //大数组分成两个小数组递归
top_down_mergesort(t, lo, mid);
top_down_mergesort(t, mid+1, hi);
_merge(t, lo, mid, hi); //两个小数组归并成大数组
}
void bottom_up_mergesort(int *t, int lo, int hi) //自底向上的归并排序(不需递归)
{
int tlen = hi - lo + 1; //t的长度
for(int sz = 1; sz < tlen; sz *= 2) //每个子数组的长度变化
{
for(int i = 0; i < tlen - sz; i += (sz+sz)) //每一对要归并的数组的起始位置
{
int _hi;
if(hi <= i + 2*sz -1) //判断边界
_hi = hi;
else
_hi = i + 2*sz - 1;
_merge(t, i, i+sz-1, _hi); //进行归并
}
}
}