首先归并排序的非递归和递归一样,都需要开辟一个数组为了进行更小的值的尾插,尾插结束后,再将这个有序数组拷贝到原数组中。
void MergeSortNonR(int* a, int n)
{
// 首先归并排序的非递归和递归一样,都需要开辟一个数组为了进行更小的值的尾插,尾插结束后,再将这个有序数组拷贝到原数组中。
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc fail");
exit(-1);
}
// 先将每次进行尾插时的左右区间的范围定为1
int rangeN = 1;
// 左右区间的范围肯定是不能大于数组的总大小了,当大于或者等于数组总大小时,循环结束。
// 并且这里也要注意,左右区间的的大小是不一定相同的,rangeN表示左右区间中最大区间的大小
// 把小于号改成小于等于号,也不会错,但是会多此一举,因为rangeN如果等于n了顺序一定全部排好了
// 在while循环中,rangeN循环一次它的大小就变为原来的两倍
while (rangeN < n)
{
// 每次循环排一组
for (int i = 0; i < n; i += rangeN * 2)
{
int begin1 = i, end1 = i + rangeN - 1;
int begin2 = i + rangeN, end2 = i + 2 * rangeN - 1;
int j = i;
// 可能存在数组越界的行为
// 有两种方法可以处理数组越界
// 第一种是改变区间的大小,这种方法可以适应后续的部分拷贝和全部拷贝
// 第二种方法是当区间大小不符合要求时,循环结束,此次rangeN的for循环结束
// 注意,第二种方法不支持后续的全部拷贝,因为后面的一部分区间没拷贝到tmp中,tmp中仍是随机值
if (end1 >= n)
{
break;
}
else if (begin2 >= n)
{
break;
}
else if (end2 >= n)
{
end2 = n - 1;
}
//if (end1 >= n)
//{
// end1 = n - 1;
// begin1 = n;
// end2 = n - 1;
//}
//else if (begin2 >= n)
//{
// end2 = n - 1;
//}
//else if (end2 >= n)
//{
// end2 = n - 1;
//}
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] <= a[begin2])
tmp[j++] = a[begin1++];
else
tmp[j++] = a[begin2++];
}
while (begin1 <= end1)
tmp[j++] = a[begin1++];
while (begin2 <= end2)
tmp[j++] = a[begin2++];
memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
}
//memcpy(a, tmp, sizeof(int) * n);
rangeN *= 2;
}
free(tmp);
tmp = NULL;
}