一、思想
1、基于分治策略
把大规模问题划分为小规模问题,集中起来解决小规模的问题,从而导致整体的大规模问题被解决。
2、核心
归并排序就是分和合的过程,为什么会这么说??他就是想办法在怎样的情况下让他是有序的,如果是一个数据,那我们是不是可以认为他不用排序都是有序的。
分:把数组中的数据划分成一组一组的小组,并且保证组内有序。
合:把分好的小组又进行合并,合并后的小组要保证组内有序。
3、怎样划分小组?
我们对每一个小组都去找它的中间值,也就是( right - left ) / 2 + left
,其中,right 为小组的第一个元素下标,left 为小组的最后一个元素下标。
划分小组的过程又是一个递归的过程。
4、分和合的图解过程
结合变量我们来分析一下,如何从第二次合并到第三次合并的:
(1)现在有4个小组,结合第一次到第二次的划分我们发现,要将前两组合并,胡两组合并,最终合并为两个组。
(2)开辟一个数组 tmp 作为排序后结果保存的临时数组;
mid 标识拆分时的中间位置;k 标志tmp的初始位置
i 标识左小组的第一个元素位置;j 标识右小组的第一个元素位置
(3)arr[0] < arr[3],将arr[0]存入tmp[k]中,i++,k++;
(4)arr[1] < arr[3],将arr[1]存入tmp[k]中,i++,k++;
(5)arr[2] < arr[3],将arr[2]存入tmp[k]中,i++,k++;
(6)此时i++的时候第一个小组越界了,所以就将与它合并的小组直接存入tmp接下来的位置中
(7)此时在调用一个函数,进行右边两个小组的合并,而这个函数不断地对有不止一个元素的数组进行划分,所以就要用到递归。
(8)arr[6] < arr[9],将arr[6]存入tmp[k]中,i++,k++;
(9)arr[7] > arr[9],将arr[9]存入tmp[k]中,j++,k++;
(10)arr[7] < arr[10],将arr[7]存入tmp[k]中,i++,k++;
(11)arr[8] > arr[10],将arr[10]存入tmp[k]中,j++,k++;
5、总结
(1)如果第一个小组越界了,但是第二个小组还没有遍历完,那就直接将第二组剩余的数据存入tmp中。
(2)比较两个数据的大小,哪边数据小,取哪边数据,哪边的下标- -。
(3)start 标记每组的起始位置,end 标记每组的末尾位置,划分后,被分为[start,mid] 和 [mid+1,end]两个小组。
(4)最后将在 tmp 排好的数据直接存入原数组中。
二、代码实现
#include<stdio.h>
#include<stdlib.h>
void Merge(int arr[], int tmp[], int start,int mid, int end)//合并小组并排序
{
int i = start;//i标识左小组的第一个元素位置
int j = mid + 1;//j标识右小组的第一个元素位置
int k = start;//tmp当前小组存放的起始位置
while (i < mid + 1 && j < end + 1)//左小组越界或右小组越界才能退出
{
if (arr[i] <= arr[j])
{
/*tmp[k] = arr[i];
k++;
i++;*/
tmp[k++] = arr[i++];
}
else
{
tmp[k++] = arr[j++];
}
}
while (j < end + 1)//右边小组没有越界
{
tmp[k++] = arr[j++];
}
while (i < mid + 1)//左边小组没有越界
{
tmp[k++] = arr[i++];
}
for (i = start; i <= end; i++)
{
arr[i] = tmp[i];
}
}
void MergeS(int arr[], int tmp[], int start, int end)//划分小组
{
if (start < end)
{
int mid = (start+end)/2;
MergeS(arr, tmp, start, mid);
MergeS(arr, tmp, mid + 1, end);
Merge(arr, tmp, start, mid, end);
}
}
void MergeSort(int arr[], int len)
{
int *tmp = (int *)malloc(sizeof(int)*len);//排序后结果保存的临时数组
MergeS(arr, tmp, 0, len - 1);
free(tmp);
}
int main()
{
int arr[] = { 12, 3, 21, 32, 1, 34, 12, 35, 34 };
int len = sizeof(arr) / sizeof(arr[0]);
MergeSort(arr, len);
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}