归并排序
我们先把数组分成两半部分,如果数组左半部分有序,右半部分也有序,那么我们就可以使用归并
例如下图
那么如何归并左右部分呢?(下面我们以升序为例子)
算法如下:
1.我们利用两个指针(bagin1,bagin2),分别指向左右部分的第一个元素。
2.比较arr[bagin1] arr[bagin2] 的大小,把小的移动到临时数组里面,然后对应的指针++,然后循环起来直到其中一个数组移动完,循环结束。
3.如果两半部分的数组个数不相等,必然有一个没有移动完,我们需要检查是那个没有移动完,然后把没有移动完的数据直接拷贝到临时数组里面。(为什么能直接拷贝?因为已经部分有序,当循环结束时,有数没有移动完,那么这些数一定比移动完的数大)
4.把临时数组里面整体排序好的的数拷贝到原来数组中,归并完毕。
部分步骤如图:
..........................
那么有同学要说了,如果左右部分没有序怎么办?
这不是老套路了嘛,递归呗。
递归终止条件:当左右区间区间只有一个值或者没有值时,结束递归。
具体代码如下(如果有同学不理解递归,请自行画递归展开图,你会恍然大悟的):
#include<stdio.h>
#include<stdlib.h>
//归并排序
void Merge_Sort(int *arr,int left,int right,int *temp)
{
if(left >= right) //left == right 区间只有一个值不需要归并了
{
return;
}
int mid=(left+right)>>1;
//假设 [left,mid] [mid+1,right]有序,那我们就可以归并了
Merge_Sort(arr,left,mid,temp);
Merge_Sort(arr,mid+1,right,temp);
int bagin1=left,end1=mid;//归并
int bagin2=mid+1,end2=right;
int index=left;
while(bagin1<=end1 && bagin2<=end2)
{
if(arr[bagin1] < arr[bagin2])
{
temp[index++]=arr[bagin1++];
}
else
{
temp[index++]=arr[bagin2++];
}
}
//判断哪个区间没结束,就把那个区间直接放到temp中
while(bagin1 <= end1)
{
temp[index++]=arr[bagin1++];
}
while(bagin2 <= end2)
{
temp[index++]=arr[bagin2++];
}
//拷贝回arr
for(int i=left; i<=right; i++)
{
arr[i]=temp[i];
}
}
void MergeSort(int *arr,int Size)
{
int *temp=(int*)malloc(sizeof(int)*Size);
Merge_Sort(arr,0,Size-1,temp);//创建一个子函数方便递归
free(temp);
}
int main()
{
int arr[]={5,2,1,4,3,6,9,8,7,0};
MergeSort(arr,10);
for(int i=0;i<10;i++)
{
printf("%d ",arr[i]);
}
return 0;
}