1.递归实现
void _MergeSort(int* a, int* tmp, int begin, int end)//子函数
1.if (begin >= end)
{
return;
}//开头要进行两个参数的判断,保持细节好习惯
2.下面来讲归并的具体思想:其实就是将一个数组不断二分细化,直到分为两两一组再分别进行比较并返回给上一级,接着开辟一个新数组用来暂时储存这些排序好的数字,最后用memcpy将临时数组(tmp)中排序好的数组拷贝到原数组。
3.这里是单趟排序的实现:
int mid = (begin + end) / 2;//分为两个小数组
int begin1 = begin, end1 = mid;
int begin2 = mid + 1, end2 = end;//确定遍历的头尾
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[i++] = a[begin1++];
}
else
{
tmp[i++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[i++] = a[begin2++];
}//顺序储存到新数组
4.递归实现:
_MergeSort( a, tmp, begin, mid );
_MergeSort( a, tmp, mid+1, end );//类似于分为左右树,但要注意递归插入的位置
下面着重分析一下为什么不以下面这种方式递归:
假设begin=0,end=6;那么mid=3;再细分,第一个数组中就会得到mid=2,即出现【2,3】这个小区间,但接着算下去你会发现【2.3】无法再分,所以会陷入死循环
_MergeSort( a, tmp, begin, mid-1 );
_MergeSort( a, tmp, mid, end );
5.拷贝到原数组
memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));//注意memcpy前者是要拷贝到的地方(目的地),后者是用来拷贝的源
到此,子函数写完。
———————————————————————————————————————————
递归主函数
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc fail");
return;
}
_MergeSort(a, tmp, 0, n - 1);
free(tmp);
tmp = NULL;
}
这里是最后的成品:
2.非递归实现
单趟排序的思路与上文相同。
这里我们用循环来解决问题————引入gap变量,通过gap的递增(每次*2)来完成:
元素为一的子数组两两归并(gap=1)
元素为二的子数组两两归并(gap=2)
元素为四的子数组两两归并(gap=4)
.............
其中随着gap的不断*2,肯定会出现越界问题,以下代码就是解决之法:
if (begin2 >= n)
{
break;
}
if (end2 >= n)
{
end2 = n - 1;
}
越界无非是end1,begin2或者end2越界。
end1,begin2越界归为通一类,这二者越界即代表第二个数组没有需要访问的数字,直接break即可。
但若只有end2越界,则需重新确定end2的值,以便运算。