11:归并排序(重要)
11:归并排序(重要)
时间复杂度:O(N * logN)
与O(N^2)排序算法的比较:
1、O(N^2)大量浪费了比较行为。
2、归并排序,当左组和右组的排序排好后,在merge的时候,
左组数之间是没有比较的。
是左组数与右组数的比较。
每一次比较行为都变成了结果并且再传递下去。
算法流程:
f(arr, L, R)
1、求中点M
2、左部分有序f(arr, L, M);
3、右部分有序f(arr, M+1, R);
4、想办法让左右两部分合并有序,也就是merge过程;
从Master公式的角度来看,时间复杂度:分为左右等规模的2部分
T(N) = 2 * T(N/2) + O(N)
a = 2, b = 2, d = 1
O(N * logN)
递归写的Merge
1 // 递归方法实现
2 public static void mergeSort1(int[] arr) {
3 if (arr == null || arr.length < 2) {
4 return;
5 }
6 process(arr, 0, arr.length - 1);
7 }
8
9 // 请把arr[L..R]排有序
10 // l...r N
11 // T(N) = 2 * T(N / 2) + O(N)
12 // O(N * logN)
13 public static void process(int[] arr, int L, int R) {
14 if (L == R) { // base case
15 return;
16 }
17 int mid = L + ((R - L) >> 1);
18 process(arr, L, mid);
19 process(arr, mid + 1, R);
20 merge(arr, L, mid, R);
21 }
1 public static void merge(int[] arr, int L, int M, int R) {
2 int[] help = new int[R - L + 1];
3 int i = 0;
4 int p1 = L;
5 int p2 = M + 1;
6 while (p1 <= M && p2 <= R) {
7 help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
8 }
9 // 要么p1越界了,要么p2越界了
10 while (p1 <= M) {
11 help[i++] = arr[p1++];
12 }
13 while (p2 <= R) {
14 help[i++] = arr[p2++];
15 }
16 for (i = 0; i < help.length; i++) {
17 arr[L + i] = help[i];
18 }
19 }
O(N2)的排序,大量浪费比较行为。
而O(N * logN)merge过程:
左组的比较过程,固定化
右组的比较过程,固定化,
在merge的时候,左组和左组,右组和右组内部是没有比较的,
是左组某个指针对右组某个指针的比较,所以比较行为每次都变成结果再传递。