1.归并排序思想:
以2路归并为例,一个有n个记录的序列可以看作n个长度为1的有序子序列,将其两两合并成n/2(向上取整)个长度为2或1的有序序列,当有奇数个记录时为1,重复归并,直到得到一个长度为n的有序序列。
2.归并排序的复杂度:
递归:时间复杂度O(nlongn),空间复杂度O(n+longn)
非递归:时间复杂度O(nlongn),空间复杂度O(n)
所以用到归并排序,还是优先考虑非递归吧。
3.递归实现
1 public void mergeSort1(int[] data){ 2 msort(data,0,data.length-1); 3 } 4 5 public void msort(int[] data, int start, int end){ 6 if(start < end){ 7 int mid = (start + end) >>> 1; 8 msort(data,start,mid); 9 msort(data,mid+1,end); //当mid+1 == end时,子序列长度为1,退出msort,进入merge()排序 10 merge(data,start,mid,end); 11 } 12 } 13 14 public void merge(int[] data, int start, int mid, int end){ 15 int s1 = start; //子序列1在data[]的起始下标 16 int s2 = mid + 1; //子序列2在data[]的起始下标 17 int[] tmp = new int[end - start +1]; 18 int index = 0; //临时数组tmp的下标 19 while((s1 <= mid) && (s2 <= end)){ //两个序列都还没有完全放入tmp[]中 20 if(data[s1] < data[s2]) tmp[index++] = data[s1++]; 21 else tmp[index++] = data[s2++]; 22 } 23 while(s1 <= mid){ //第2个序列已经完全放入tmp中,由于s1本身是有序的,将s1剩下的元素直接放入 24 tmp[index++] = data[s1++]; 25 } 26 while(s2 <= end){ 27 tmp[index++] = data[s2++]; 28 } 29 for(int i = 0; i < tmp.length; i++){ 30 data[start++] = tmp[i]; 31 } 32 }
4.非递归实现
1 public void mergeSort2(int[] data){ 2 int k = 1; 3 while(k < data.length){ 4 merge(data,k); 5 k *= 2; 6 } 7 } 8 9 public void merge(int[] data, int len){ 10 int s1 = 0; 11 int e1 = s1+len-1; 12 int s2 = e1+1; 13 int e2 = s2+len-1 < data.length ? s2+len-1 : data.length-1; 14 int[] tmp = new int[data.length]; 15 int index = 0; 16 while(s2 < data.length){ //第一种情况存在两个序列 17 while((s1 <= e1) && (s2 <= e2)){ 18 if(data[s1] < data[s2]) tmp[index++] = data[s1++]; 19 else tmp[index++] = data[s2++]; 20 } 21 while(s1 <= e1){ 22 tmp[index++] = data[s1++]; 23 } 24 while(s2 <= e2){ 25 tmp[index++] = data[s2++]; 26 } 27 s1 = e2 + 1; //处理下一组的两个子序列 28 e1 = s1 + len -1; 29 s2 = e1 + 1; 30 e2 = s2 + len - 1 < data.length ? s2 + len -1 : data.length -1; 31 } 32 while(s1 < data.length){ //第二种情况,只剩下一个子序列了 33 tmp[index++] = data[s1++]; 34 } 35 for(int i = 0; i < data.length; i++){ 36 data[i] = tmp[i]; 37 } 38 }