0 mid right= nums.length-1 mid=(right+left)/2
递 : 34 51 78 88 9 11 37 32
/\ /\
34 51 78 88 9 11 37 32
/\ /\ /\ /\
34 51 78 88 9 11 32 37
归 \/ \/ \/ \/ 递归出口: if(left==right) return;
34 51 78 88 9 11 32 37
\/ \/
34 51 78 88 9 11 32 37
\/
9 11 32 37 34 51 78 88
递: sort =sort1(0,mid) ,sort1(mid+1,right)
归: merge(int nums[],int left,int mid,int right,int tmp[]) 即合并
merge 详解 以归的最后一步说明
tmp数组 34 51 78 88 9 11 32 37
left right
int tmp[]=new int [nums.length]
先把刚刚声明的数组用原数据拷贝
for(int k=left;k<=right;k++){
tmp[k]=nums[k];}
若遍历i之后 i的值为mid+1,说明左边的拷贝完,j之后的数据就可以直接拷到nums数组了。
若遍历j之后 j的值为mid+1,说明右边的拷贝完,左边的数据就可以直接拷到nums数组了。
若i,j没有到边界(即上面那两个值),则再进行比较:
1.若 tmp[i]比tmp[j]还大, 那么我们将小的 tmp[i]拷贝到nums数组,不要忘了i++。
2.反之,即tmp[i]比tmp[j]还小,我们 将小的tmp[j]拷贝到nums数组,同时加j++。
package stack;
import java.util.Arrays;
public class GuiBing {
public void sort(int nums[]) {
int tmp[]=new int[nums.length]; //这里申请一个数组,避免每次申请数组,造成空间上的浪费
sort1(nums,0,nums.length-1,tmp);
}
private void sort1(int[] nums, int left, int right, int[] tmp) {
if(left==right) {
return;
}
int mid=(left+right)/2;
sort1(nums,left,mid,tmp); //问题1
sort1(nums,mid+1,right,tmp);
merge(nums,left,mid,right,tmp);
}
private void merge(int[] nums, int left, int mid, int right, int[] tmp) {
for(int i=left;i<=right;i++){
tmp[i]=nums[i];
}
int i=left;
int j=mid+1;
for(int k=left;k<=right;k++) {
if(i==mid+1) {
nums[k]=tmp[j++];
}
else if(j==right+1) {
nums[k]=tmp[i++];
}
else if(tmp[i]<=tmp[j] ) {
nums[k]=tmp[i++];
}
else {
nums[k]=tmp[j++];
}
}
}
public static void main(String args[]) {
GuiBing GB=new GuiBing();
int nums[]= {34,51,78,88,9,11,37,32};
GB.sort(nums);
System.out.println(Arrays.toString(nums));
}
}
从归并排序再次体会编程的递归思想分治:
当程序递归到left==right 时,即此时的数组只有一个元素,那么进行归的操作,上一步是系统栈存的是两个元素的数组,进行sort1方法中
的merge,这里注意每次merge调用两次,因为大问题拆分为了两个小的子问题。