今天我们来说一说常见的七大排序中的最后一个----归并排序.
归并排序的思想就是大化小.
递归版本
首先我们要做的就是把数据一直对半分,直到分成了一组只有一个:
不知道兄弟们还记不记得之前我们说过的两个有序数组的合并?只有一个数据时,自然而然可以看成是有序的,然后我们就可以慢慢地合并了:
//合并的逻辑并不复杂,只是有些需要考虑:
//之前我们说了,数据都是对半分的,那么第一组就应该是前半段,第二组就是后半段
//这就必然涉及到中间的下标
public void add(int[]arr,int left,int mid,int right){
int[]tmp=new int[right-left+1];
int s1=left;
int s2=mid+1;
int k=0;
while (s1<=mid&&s2<=right){
while (s1<=mid&&s2<=right&&arr[s1]<arr[s2]){
tmp[k++]=arr[s1++];
}
while (s1<=mid&&s2<=right&&arr[s1]>arr[s2]){
tmp[k++]=arr[s2++];
}
}
//当一组数据排好时,我们不知道另一组数据的情况,还是需要排一下的
while (s1<=mid){
tmp[k++]=arr[s1++];
}
while (s2<=right){
tmp[k++]=arr[s2++];
}
//这里arr的下标需要处理的原因是因为,如果此时我们在后半段数据时
//很有可能下标是不对应的,你能明白我的意思吗?前面会有left的一个空隙
for (int i = 0; i < tmp.length; i++) {
arr[i+left]=tmp[i];
}
}
public void merge(int[]arr,int left,int right){
if(left>=right)return;
int mid=(left+right)/2;
//先分
merge(arr,left,mid);
merge(arr,mid+1,right);
//再合并
add(arr,left,mid,right);
}
public void mergeSort(int[]arr){
merge(arr,0,arr.length-1);
}
非递归
public void mergeSort1(int[]arr){
int gap=1;
//gap就表示每一次归并组内的个数,当归并整个数组长度时,就完了
while(gap<=arr.length){
for (int i = 0; i < arr.length-1; i+=gap*2) {
//i就表示每次归并的起始
int left=i;
int mid=left+gap-1;
if(mid>arr.length-1){
mid=arr.length-1;
}
int right=mid+gap;
if(right>arr.length-1){
right=arr.length-1;
}
add(arr,left,right);
}
// 我们这里不需要自己分组是因为,我们就是从一组的情况下开始的
//所以我们也要自己调整gap
gap*=2;
}
}
好了,兄弟们,有了学习二叉树的知识,其实我们的归并排序就显得不是那么困难了,尤其是看完了我的这篇博客,你们应该会有一个更加清晰的认识吧!
百年大道,你我共勉!