归并排序
1.归并的思想
虽然官方给的定义说归并是分治法,但是,我的理解是递归。
有句话说得好,人理解递推,神理解递归。
最短的三行代码也是最难的,因为牵扯到了回溯。
归并和快排都是分治,归并排序和快排不一样的是,快排只有向下的操作,而没有回溯。
还有就是,归并排序每次分割都是中点,而快排的分割是在左右指针相遇的地方。
话不多说,开始撸代码。。。
2.代码分析
(1)合并操作
对于一个左边一半和右边一半分别有序的数组,合并成一个新的整体有序的数组,需要注意的是,这里需要一个和原数组一样大的辅助空间。
int Temp[MaxSize]; //辅助数组
//arr[left...mid] 有序 arr[mid+1...right]有序
void Merge(int arr[],int left,int right)
{
int mid=(left+right)/2;
int i=left; //指向原数组左半部分
int j=mid+1; //指向原数组右半部分
int k=0; //用来指向辅助数组
while(i<=mid&&j<=right) //此时左右两半数组都没到顶
{
if(arr[i]<=arr[j])
Temp[k++]=arr[i++];
else
Temp[k++]=arr[j++];
}
while(i<=mid) //右半数组比完了,把剩余左半数组直接复制到Temp数组后面
Temp[k++]=arr[i++];
while(j<=right) //同理
Temp[k++]=arr[j++];
k=0; //此时Temp数组是一个完整有序的数组,指针指向Temp数组开始的地方
for(int q=left;q<=right;q++)
arr[q]=Temp[k++]; //把Temp数组从头到尾 复制 到 arr数组中
}
(2)递归操作
学递归的时候,最最最最难理解的就是回溯了,短短的三行代码,智慧的凝结啊。
void Merge_Sort(int arr[],int left,int right)
{
if(left==right) //表示该区间就一个数了,不能向下递归了,这个子区间已经有序了,可以向上回溯了
return ;
int mid=(left+right)/2;
//如果没有执行if里面 说明这个区间足够大,不能保证左右子区间 都分别有序
Merge_Sort(arr,left,mid); //进左子区间
Merge_Sort(arr,mid+1,right); //进右子区间
//执行完上面两个函数,说明此时左右两个子区间已经分别有序,符合Merge的前提条件,可以合并了,也就是所谓的回溯
Merge(arr,left,right);
}
最近压力有点大,很多东西要做,都不想做,解压的方法就是写代码。。。