归并排序:归并排序有递归版和非递归版,在学习归并排序之前,我希望你对合并两个有序数组有一定的了解,这可以帮助你理解归并排序。
归并排序递归版
归并排序递归版的思想:需要一个temp数组,先将有序的最小子序列两两归并到temp数组,得到有序的子序列段,接着把有序的子序列段拷贝回原数组。然后把子序列段看成子序列,再两两归并到temp数组,得到更大的子序列段,再拷贝回原数组;重复上述过程即可。
怎么保证子序列段有序呢?
从最小子序列开始归并,有序最小子序列中只有一个数据。就相当于把待排序的整体数据分解为一个一个的数据,然后两两归并,两两归并完之后得到的子序列段中有两个数据,再把两个数据组成的子序列段看成子序列,再次两两归并,就能保证子序列段有序了。
归并排序大概流程图:
归并排序递归版代码:递归版本的归并排序需要一定的二叉树的知识支撑理解,需要掌握二叉树的几个遍历;这里更像是后续遍历,此处不在赘述。递归版本的归并排序不用担心越界问题。
void SubMergeSort(int* arr, int* temp, int begin, int end)
{
if (begin >= end)//当begin大于end时区间不存在,相等时子序列段中只有一个数据。
return;
int mid = (end + begin) / 2;//递归分解整个待排序的数组
// [begin, mid][mid+1, end]
SubMergeSort(a, tmp, begin, mid);//递归左半区间
SubMergeSort(a, tmp, mid+1, end);//递归右半区间
// 归并到temp数据组,再拷贝回去
int begin1 = begin, end1 = mid;//begin1到end1是一个子序列
int begin2 = mid+1, end2 = end;//begin2到end2是一个子序列
int index = begin;//index用于控制归并到temp数组中的位置
while (begin1 <= end1 && begin2 <= end2)//归并过程,选小的尾插
{
if (a[begin1] < a[begin2])
{
tmp[index++] = a[begin1++];
}
else
{
tmp[index++] = a[begin2++];
}
}
//两组数据归并,总有一组数组没有全部进入temp数组,把剩余数据全部尾插到temp数组中
while (begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = a[begin2++];
}
// 拷贝回原数组,拷贝回原数组也可以用循环。
memcpy(arr + begin, temp + begin, (end - begin + 1)*sizeof(int));
}
void MergeSort(int* arr, int len)//arr表示待排序的数组,len表示数组长度
{
int* temp = (int*)malloc(sizeof(int) * len);//归并两个子序列需要一个temp
if (temp == NULL)
{
printf("malloc fail");
return;
}
SubMergeSort(arr, temp, 0, len - 1);//实现排序的部分
free(temp);//堆内存申请的空间一定要记得释放
}
归并排序非递归版
归并排序非递归版的思想:
非递归版本的归并排序的思想和递归版的差不多,区别在于少了递归分解待排序数组区间这一步,而是定义一个变量gap代表子序列中数据的个数,gap一开始等于1,代表一个数据和一个数据归并,归并完之后gap扩大两倍,此时gap等于2,代表两个数据和两个数据归并,重复上述过程,控制gap最大不超过数据个数的一半。
非递归版代码:
void SubMergeSort(int* arr, int* temp, int len)
{
int gap = 1;
while (gap < len)
{
for (int i = 0; i < len; i += 2 * gap)
{
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
int index = i;
if (end1 >= len)//end1越界,说明第二组数据不存在,这组数据可以不用排了
break;
if (begin2 >= len)//begin2越界,说明第二组数据不存在,这组数据可以不用排了
break;
if (end2 >= len)//end2越界,调整end2
end2 = len - 1;
//归并到temp数组
while (begin1 <= end1 && begin2 <= end2)
{
if (arr[begin1] <= arr[begin2])
{
temp[index++] = arr[begin1++];
}
else
{
temp[index++] = arr[begin2++];
}
}
while (begin1 <= end1)
{
temp[index++] = arr[begin1++];
}
while (begin2 <= end2)
{
temp[index++] = arr[begin2++];
}
//拷贝回原数组
memcpy(arr + i, temp + i, sizeof(int) * (end2 - i + 1));
}
gap *= 2;
}
}
void MergeSortNoR(int* arr, int len)
{
int* temp = (int*)malloc(sizeof(int) * len);
if (temp == NULL)
{
printf("malloc fail");
return;
}
SubMergeSort(arr, temp, len);
free(temp);
}
看到这了我得给你点个赞,希望可以帮助到你哦。