基本思想:
二路归并排序主要运用了“分治算法”,分治算法就是将一个大的问题划分为n个规模较小而结构相似的子问题。
二路归并排序主旨是“分解”与“归并”:
分:
1.一直分两组,分别对两个数组进行排序(根据上层对下层在一组的数据通过临时数组排序,再将有序数组挪回上层数组中)。
2. 循环第一步,直到划分出来的“小组”只包含一个元素,只有一个元素的数组默认为已经排好序。
合:(合并时,站在上层合并下层(使组内有序))
1.将两个有序的数组合并到一个大的数组中。
2.从最小的只包含一个元素的数组开始两两合并。此时,合并好的数组也是有序的。最后把小组合成一个组。
图解:
注:此图来自网络,谢谢帮助理解二路归并排序思想
代码实现:
//根据上层对下层在一组的数据通过临时数组排序,再将有序数组挪回上层数组中
void Merge(int arr[], int tmp[],
int startIndex, int midIndex, int endIndex)
{
//初始化
int leftIndex = startIndex;
int rightIndex = midIndex + 1;
int tmpIndex = startIndex;
// 不越界
while (leftIndex < midIndex + 1 && rightIndex < endIndex + 1)
{
if (arr[leftIndex] > arr[rightIndex])
{
tmp[tmpIndex++] = arr[rightIndex++];
}
else
{
tmp[tmpIndex++] = arr[leftIndex++];
}
}
while (leftIndex < midIndex + 1)//当右越界
{
tmp[tmpIndex++] = arr[leftIndex++];
}
while (rightIndex < endIndex + 1)//当左越界
{
tmp[tmpIndex++] = arr[rightIndex++];
}
for (int i = startIndex; i < endIndex + 1; ++i)//将临时数组中的有序数据“挪回”原数组
{
arr[i] = tmp[i];
}
}
//将arr[]分组、排序过程
//左分 递归,右分 排序 回溯的过程
void MyMerge(int arr[], int tmp[],
int startIndex, int endIndex)
{
if (startIndex < endIndex)
{
int midIndex = (endIndex + startIndex) / 2;
MyMerge(arr, tmp, startIndex, midIndex);//左分
MyMerge(arr, tmp, midIndex + 1, endIndex);//右分
Merge(arr,tmp,startIndex,midIndex,endIndex);//排序
}
}
void MergeSort(int arr[], int len)
{
int *tmp = (int*)malloc(sizeof(int)*len);//动态开辟tmp数组
MyMerge(arr, tmp, 0, len - 1);//将arr[]分组、排序过程
}
void MergeShow(int arr[], int len)
{
for (int i = 0; i < len; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = { 265, 3, 16, 13, 16, 13, 1, 36, 6, 66, 81, 78 };
int len = sizeof(arr) / sizeof(arr[0]);
MergeSort(arr, len);
MergeShow(arr,len);
return 0;
}
总结:
时间复杂度:平均O(nlog2n),最好O(nlog2n),最坏O(nlog2n)
空间复杂度:O(n)
稳定