归并排序:
1.算法:将两段有序的数据合并为一段有序的数据,直到所有的数据有序
2.先一个一个有序,然后两个两个有序,再四个四个有序,直到所有的数据有序
3.一次归并的时间复杂度为O(n),遍历了一遍arr数组,一共要遍历logn次数组,所以时间复杂度O(nlogn),空间复杂度O(n),稳定(没有跳跃式的交换)
//打印
void Show(int* arr, int len)
{
for (int i = 0; i < len; ++i)
{
cout << arr[i] << " ";
}
cout << endl;
}
//一次归并排序
static void Merge(int *arr,int len,int gap)
{
int low1 = 0;//第一个归并段的起始下标
int high1 = low1+gap-1;//第一个归并段的结束下标
int low2 = high1+1;//第二个归并段的起始下标
int high2 = low2+gap-1<len?low2+gap-1:len-1;//第二个归并段的结束下标 如果high2的下标可能越界
int i = 0;//brr的下标
//创建和arr长度相等的动态内存
int *brr = (int *)malloc(sizeof(int) * len);
assert(brr != NULL);
//有两个归并段
while(low2<len)//low2<len才能说明有两个归并段
{
//两个归并段都还有数据
while(low1<=high1 && low2<=high2)//总是比较len1和len2,把小的保存在brr中
{
if(arr[low1]<=arr[low2])//low1小,把low1保存在
{
brr[i++] = arr[low1++];
}
else//low2小
{
brr[i++] = arr[low2++];
}
}
//如果一个归并段的数据已经完成了,另一个归并段还有数据,就把数据全部依次放到brr中,这两个while只会运行一个
while(low1<=high1)
{
brr[i++] = arr[low1++];
}
while(low2<=high2)
{
brr[i++] = arr[low2++];
}
//下两个归并段,这时的high2就是第二个归并段的low1
low1 = high2+1;
high1 = low1+gap-1;
low2 = high1+1;
high2 = low2+gap-1<len?low2+gap-1:len-1;
}
//只有一个归并段,直接保存,一个归并段本身就是有序的
while(low1<len)//不能用high1,因为high1可能越界
{
brr[i++] = arr[low1++];
}
//将归并好的数据拷贝到arr中
for(int i = 0;i<len;i++)
{
arr[i] = brr[i];
}
free(brr);
}
//时间复杂度为O(nlogn)
void MergeSort(int *arr,int len)
{
for(int i = 1;i<len;i*=2)//O(logn)
{
Merge(arr,len,i);
}
}
int main()
{
int arr[] = { 56,12,78,34,23,100,45,67,89,90 };
int n = sizeof(arr) / sizeof(arr[0]);
MergeSort(arr, n);
Show(arr, n);
return 0;
}
非递归写法
void Print_Ar(int* br, int n)
{
if (br == NULL || n < 1) return;
for (int i = 0; i < n; ++i)
{
cout << br[i] << " ";
}
cout << endl;
}
void Merge(int* src, int* dest, int left, int m, int right)
{
int i = left;
int j = m + 1;
int k = left;
while (i <= m && j <= right)//两个块都还有数据
{
dest[k++] = src[i] <= src[j] ? src[i++] : src[j++];
}
while (i <= m)//第一个块可能还省有数据
{
dest[k++] = src[i++];
}
while (j <= right)//第二个块可能还省有数据
{
dest[k++] = src[j++];
}
}
void MergePass(int* src, int* dest, int n, int s)
{
int i = 0;
for (; i + 2 * s - 1 < n; i = i + 2 * s)//两个块都有数据
{
Merge(src, dest, i, i + s - 1, i + 2 * s - 1);
}
if ( i + s - 1< n - 1 )//一个块有数据
{
Merge(src, dest, i, i + s - 1, n - 1);
}
else//不够一个块的拷贝下来,肯定也是有序的
{
for (int j = i; j < n; ++j)
{
dest[j] = src[j];
}
}
}
void MergeSort(int* br, int n)
{
if (br == NULL || n < 2)return;
int* tmp = new int[n];
int s = 1;//每个块中有几个数据
while (s < n)
{ //br和tmp两个地方来回倒
MergePass(br, tmp, n, s);
s += s;
MergePass(tmp, br, n, s);
s += s;
}
delete[]tmp;
}
int main()
{
int ar[] = { 56,12,78,95,34,23,100,45,67,89 };
int n = sizeof(ar) / sizeof(ar[0]);
Print_Ar(ar, n);
MergeSort(ar, n);
Print_Ar(ar, n);
return 0;
}