前几天卡一个警告卡了几天,vs2019真让人头秃
直接进入正题吧。
之前介绍的排序算法:
- 【算法】插入排序——希尔排序+直接插入排序_Rinne’s blog-CSDN博客
- 【算法】选择排序——堆排序+直接选择排序_Rinne’s blog-CSDN博客
- 【算法】交换排序——快速排序+冒泡排序(更新了非递归冒泡以及优化)_Rinne’s blog-CSDN博客
归并排序
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有 序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
文章目录
- 归并排序
- 一、归并排序-递归
- 1. 图解思路
- 2. 代码
- 3. 测试
- 二、归并排序-非递归
- 1. 图解思路
- 2. 代码
- 3. 运行结果
一、归并排序-递归
1. 图解思路
时间复杂度: O(n*logn)
空间复杂度:O(n)
递归退出条件:
if (left >= right)
{
return;
}
开始作比较,放到tmp里面,再拷贝回原数组
以此类推
2. 代码
//归并排序
void _MergeSort(int* a, int left, int right, int* tmp)
{
if (left >= right)
{
return;
}
int mid = (left + right) / 2;
//左右递归,
_MergeSort(a, left, mid, tmp);
_MergeSort(a, mid + 1, right, tmp);
int begin1 = left;
int end1 = mid;
int begin2 = mid + 1;
int end2 = right;
int i = left;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] > a[begin2])
{
tmp[i++] = a[begin2++];
}
else
{
tmp[i++] = a[begin1++];
}
}
while (begin1 <= end1)
{
tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[i++] = a[begin2++];
}
//tmp数组拷贝回a
for (int j = left; j <= right; ++j)
{
a[j] = tmp[j];
}
}
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
printf("malloc fail");
exit(-1);
}
_MergeSort(a, 0, n - 1, tmp);
free(tmp);
tmp = NULL;
}
3. 测试
二、归并排序-非递归
1. 图解思路
以此类推 i = i + gap后
最后gap = 4的时候,再执行一次
但需要注意数组越界的问题,刚才的例子是以偶数数组为例
如果是奇数会存在数组越界的问题
退出循环条件:gap >= n
将刚才偶数例子去除一个数
- 情况1:
begin2 和 end2 都越界
其实就是不用归并
- 情况2:
end2 越界
将刚才偶数数组加上一个数
情况3:end1 越界
2. 代码
//归并非递归
void MergeSortNonR(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
printf("malloc fail");
exit(-1);
}
int gap = 1;
while (gap < n)
{
for (int i = 0; i < n; i += 2 * gap)
{
int begin1 = i;
int end1 = i + gap - 1;
int begin2 = i + gap;
int end2 = i + 2 * gap - 1;
int index = i;
if (end1 >= n || begin2 >= n)
{
break;
}
if (end2 >= n)
{
end2 = n - 1;
}
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[index++] = a[begin1++];
}
else
{
tmp[index++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = a[begin2++];
}
//tmp数组拷贝回a
for (int j = i; j <= end2; ++j)
{
a[j] = tmp[j];
}
}
gap *= 2;
}
free(tmp);
tmp = NULL;
}
vs2019可能会出现
奇怪的警报,但是我测试了很多用例都没事
可能是编译器错误