从本文开始就要介绍O(nlogn)复杂度级别的排序算法了,首先登场的是归并排序,这个排序可以解决一些问题,会在文章的后面给出,并且是一个经典的分治思想,即先分隔再合并,将复杂的大问题瓦解为小问题,将若干小问题解决了之后大问题也就迎刃而解了。下面我们来学习一下归并排序的基本原理。
1. 原理
归并排序(MERGE-SORT
)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer
)策略(分治法将问题分(divide
)成一些小的问题然后递归求解,而治(conquer
)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
复杂度为(nlogN
),这里采用自顶向下和递归来完成的。
归并排序的原理是,先把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
归并的前提是先把要排序的序列分为若干个字序列,然后才归并。在拆分数列的时候,就要用到拆分,直到不能再拆为止。
如一个数列{9,8,7,6,5,4,3,2,1}
先分成{9,8,7,6,5}和{4,3,2,1}
然后再分成{9,8,7}和{6,5}和{4,3}和{2,1}
然后再分{9,8}、{6}、{5}、{4}、{3}、{2}、{1}
然后再合并起来,小在的前面,大的在后面,没有比较的在后面填充数列。
具体如何合并的呢?下面展示的最后的一步合并过程:
我们注意到,归并排序是需要额外的空间来辅助的。动态图为:
2. 代码
2.1 左右分开
1 2 3 4 5 6 7 8 9 10 11 12 13
| public static void sort(int[] a, int low, int high) { int mid = low + (high - low)/2; if (low < high) { sort(a, low, mid); sort(a, mid + 1, high); merge(a, low, mid, high); }
}
|
2.2 合并过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public static void merge(int[] a, int low, int mid, int high) { int[] temp = new int[high - low + 1]; int i = low; int j = mid + 1; int k = 0; while (i <= mid && j <= high) { if (a[i] < a[j]) { temp[k++] = a[i++]; } else { temp[k++] = a[j++]; } } while (i <= mid) { temp[k++] = a[i++]; } while (j <= high) { temp[k++] = a[j++]; } for (int k2 = 0; k2 < temp.length; k2++) { a[k2 + low] = temp[k2]; } }
|
对于它的理解,一句话就是先对半分,分到不能分为止,然后再倒过来将卡擦分开的两组数进行比较合并成有序序列,最终逐渐合并成有序序列。
3. 归并排序应用1–小和问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
public class MergeSortApply1 { public static void main(String[] args) { int[] arr= {1,3,4,2,5}; System.out.println(merge_sort(arr)); }
public static int merge_sort(int[] arr){ if(arr == null || arr.length < 2){ return 0; } return sortProcess(arr,0,arr.length-1); }
private static int sortProcess(int[] arr, int low, int high) { if(low == high){ return 0; }
int mid = low + (high-low)/2;
return sortProcess(arr,low,mid) + sortProcess(arr,mid+1,high) + merge(arr,low,mid,high); }
private static int merge(int[] arr, int low, int mid, int high) { int[] help = new int[high-low+1]; int k = 0; int p1 = low; int p2 = mid+1; int count = 0; while(p1 <= mid && p2 <= high){ count += arr[p1] < arr[p2] ? (high-p2+1)*arr[p1] : 0; help[k++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++]; }
while(p1 <= mid){ help[k++] = arr[p1++]; } while(p2 <= high){ help[k++] = arr[p2++]; }
for(int ii=0;ii<help.length;ii++){ arr[ii+low] = help[ii]; }
return count; }
}
|
4. 归并排序应用2–逆序对问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
public class MergeSortApply2 { public static void main(String[] args) { int[] arr= {1,2,3,4,5,6,7,0}; System.out.println(merge_sort(arr)); }
public static int merge_sort(int[] arr){ if(arr == null || arr.length < 2){ return 0; } return sortProcess(arr,0,arr.length-1); }
private static int sortProcess(int[] arr, int low, int high) { if(low == high){ return 0; }
int mid = low + (high-low)/2;
return sortProcess(arr,low,mid) + sortProcess(arr,mid+1,high) + merge(arr,low,mid,high); }
private static int merge(int[] arr, int low, int mid, int high) { int[] help = new int[high-low+1]; int k = 0; int p1 = low; int p2 = mid+1; int count = 0; while(p1 <= mid && p2 <= high){ count += arr[p1] > arr[p2] ? (high-p2+1) : 0; help[k++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++]; }
while(p1 <= mid){ help[k++] = arr[p1++]; } while(p2 <= high){ help[k++] = arr[p2++]; }
for(int ii=0;ii<help.length;ii++){ arr[ii+low] = help[ii]; }
return count; }
}
|