1.思想
一次排序过程,将已经各自有序的两个段的数据合并一个段,并且合并后依旧有序。
第一次我们认为单个数据是有序的,一个数据就是一个段,一次排序后,两个数据就是一个有序数据段,这样下一次每个有序数据段就是两个数据。最后将其合并成一个完成有序段,则整个数据就已经排序好了。
第一次数据:单个元素为一个有序数据,进行俩俩合并,合并后的每段数据是有序的。
第一次归并后的数据:
第二次归并:上图两个数据为一个有序数据段,俩俩有序数据段合并,合并后的数据段:
第三次归并:上图四个数据为一个有序数据段,俩俩有序数据段合并,合并后的数据段:
第四次归并:上图就两个有序数据段了,对齐进行归并成一个,且有序:
数据段就一个了,结束归并。
总结:其实就是不断的俩俩归并有序数据段,且归并的同时进行排序。最初一个元素看成一个有序数据段。
2.代码
2.1非递归代码:
void Merge(int* arr, int len, int width, int* brr)
{
int low1 = 0;//low1为第一段的起始位置
int high1 = low1 + width - 1; // high1为第一个段的结束位置下标
int low2 = high1 + 1;//第二段的起始位置
int high2 = low2 + width > len ? len - 1 : low2 + width - 1;//第二段的结束位置
int index = 0;
// 处理有两个归并段
while (low2 < len)//low2等于大于len就说明上一个刚好合并 或者剩一个单独的有序段
{
// 两个归并段都有未归并数据
while (low1 <= high1 && low2 <= high2)
{
if (arr[low1] < arr[low2]) brr[index++] = arr[low1++];
else brr[index++] = arr[low2++];
}
//只剩下一个归并段数据
while (low1 <= high1) brr[index++] = arr[low1++];
while (low2 <= high2) brr[index++] = arr[low2++];
low1 = high2 + 1;
high1 = low1 + width - 1;
low2 = high1 + 1;
high2 = low2 + width > len ? len - 1 : low2 + width - 1;
}
//处理只剩下一个归并段的情况
while (low1 < len)//说明剩下一个单独的有序段
{
brr[index++] = arr[low1++];
}
//将brr中的数据全部复制到arr中
for (int i = 0; i < len; ++i) arr[i] = brr[i];
}
void MergeSort(int* arr, int len)
{
int* brr = (int*)malloc(sizeof(int) * len );
assert(brr != NULL);
// i就是每个段当前的数据个数
for (int i = 1; i < len; i *= 2)
{
Merge(arr, len, i, brr);
}
free(brr);
}
int main()
{
int arr[] = { 7,88,38,7,4,34,21,23,19,40,34,39,34 };
MergeSort(arr, sizeof(arr) / sizeof(arr[0]));
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
运行结果:
2.2递归代码
#include <iostream>
#include<assert.h>
using namespace std;
void Copy(int* ar, int* br, int left, int right)
{
for (int i = left; i <= right; ++i)
{
ar[i] = br[i];
}
}
void Merge(int* br, int* ar, int left, int m, int right)
{
assert(br != nullptr && ar != nullptr);
int i = left, j = m + 1;
int k = left;
while (i <= m && j <= right)
{
br[k++] = ar[i] <= ar[j] ? ar[i++] : ar[j++];
}
while (i <= m)
{
br[k++] = ar[i++];
}
while (j <= right)
{
br[k++] = ar[j++];
}
}
void PassMerge(int* br, int* ar, int left, int right)
{
if (left < right)
{
int mid = (right - left) / 2 + left;
PassMerge(br, ar, left, mid);
PassMerge(br, ar, mid + 1, right);
Merge(br, ar, left, mid, right);
Copy(ar, br, left, right);
}
}
void MergeSort(int* ar, int n)
{
assert(ar != nullptr);
int* br = new int[n];
// int *br = (int*)malloc(sizeof(int)*n);
PassMerge(br, ar, 0, n - 1);
delete[]br;
}