什么是归并排序
归并排序(Merge Sort) 是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。—百度百科
时间复杂度:O(n log n)
空间复杂度:O(n)
实现的过程
先将元素划分到单个,之后在进行排序
代码实现
//归并排序
#include <iostream>
using namespace std;
void mergeSort(int* arr, int num);//归并排序的入口
void process(int* arr, int L, int R);//实现过程
void merge(int* arr,int L,int M,int R);//排序过程
void mergeSort(int* arr, int num)
{
if (arr == nullptr || num < 2)
{
return;
}
process(arr,0,num-1);//传入数组,第一个元素的下标,最后一个元素的下标
}
void process(int* arr, int L, int R)
{
//如果L==R,表示这个元素已经被划分到最后,成为单个元素,返回它,让它和相邻的一个单个元素去排序
if (L == R)
{
return;
}
//如果不是最后一个元素,继续调用自己,继续划分
int mid = L + ((R - L) >> 1);//找中点,为什么不用(L+R)/2,因为L+R可能会导致溢出,但R-L不会 位运算右移表示除2
//从中间划分 这里会导致函数压栈 先排好左边的,在排右边的,先最左边的一个元素和最左边的第二个元素先排序
process(arr, L, mid);
process(arr, mid + 1, R);
//排序
merge(arr, L, mid, R);
}
void merge(int* arr, int L, int M, int R)
{
//开辟辅助空间,存放排序后的数组
int* help = new int[R - L + 1];
int i = 0;//用来当辅助空间的下标
int p1 = L;//待排序的左边组的下标,用来偏移
int p2 = M + 1;//待排序的右边组的下标,用来便宜
//排序
while (p1 <= M && p2 <= R)//边界条件
{
//比较arr数组中两个下标的数值,并且在赋值给辅助空间后进行下标偏移
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
//将剩下的未比较元素赋值拷贝到辅助空间
while (p1 <= M)
{
help[i++] = arr[p1++];
}
while (p2 <= R)
{
help[i++] = arr[p2++];
}
//将辅助空间的数组拷贝到arr中,arr下标从L开始
for (i = 0;i<R-L+1;i++)
{
arr[L + i] = help[i];
}
//释放辅助空间
delete[]help;
//指针制空,避免出现野指针
help = nullptr;
}
int main()
{
int arr[] = {0,5,4,2,7,5,1};
mergeSort(arr, sizeof(arr)/sizeof(arr[0]));
//mergeSort(arr, sizeof(arr));将导致Run-Time Check Failure #2 - Stack around the variable 'arr' was corrupted.
//因为sizeof(arr)会是数组的大小而不是元素的个数,导致后面的访问下标越界
for (int a : arr)
cout << a;
return 0;
}
遇到的问题
Run-Time Check Failure #2 - Stack around the variable ‘arr’ was corrupted.
栈被破坏,一般是内存溢出
解决办法:
断点调试发现传入mergeSort函数的num = 28,但是我想传入的是数组元素的个数应该是7。
之后反应过来,sizeof数组出来的结果是数组占用的内存,应该再除以单个元素的大小。