1 介绍
1.1 实现流程
- 让左边排好序
- 让右边排好序
- 合并后整体排好序
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/26896e9869d3b237e74a83370d29b4f2.gif)
1.2 特点
2 实现
2.1 递归
public class MergeSort {
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
process(arr, 0, arr.length-1);
}
public static void process(int[] arr, int L, int R) {
if (L == R) {
return;
}
int M = L + ((R - L) >> 1);
process(arr, L, M);
process(arr, M + 1, R);
merge(arr, L, M, R);
}
public static void merge(int[] arr, int L, int M, int R) {
int[] help = new int[R - L + 1];
int i = 0;
int p1 = L;
int p2 = M+1;
while (p1 <= M && p2 <= R) {
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
while (p2 <= R) {
help[i++] = arr[p2++];
}
while (p1 <= M) {
help[i++] = arr[p1++];
}
for (i = 0; i < help.length; i++) {
arr[L + i] = help[i];
}
}
}
2.2 非递归
public class MergeSort {
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
int N = arr.length;
int mergeSize = 1;
while (mergeSize < N) {
int L = 0;
while (L < N) {
int M = L + mergeSize - 1;
if (M >= N) {
break;
}
int R = Math.min(M + mergeSize, N - 1);
merge(arr, L, M, R);
L = R + 1;
}
if (mergeSize > N / 2) {
break;
}
mergeSize <<= 1;
}
}
public static void merge(int[] arr, int L, int M, int R) {
int[] help = new int[R - L + 1];
int i = 0;
int p1 = L;
int p2 = M+1;
while (p1 <= M && p2 <= R) {
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
while (p2 <= R) {
help[i++] = arr[p2++];
}
while (p1 <= M) {
help[i++] = arr[p1++];
}
for (i = 0; i < help.length; i++) {
arr[L + i] = help[i];
}
}
}
3 归并拓展
3.1 降序对
- 题目:每个元素和他右边比他小的元素,构成的一对数
- 解法:每次归并的时候比较,左大右小出降序对
public class ReversePairs {
public static int reverse(int[] arr) {
if (arr == null | arr.length < 2) {
return 0;
}
return process(arr, 0, arr.length - 1);
}
public static int process(int[] arr, int L, int R) {
if (L == R) {
return 0;
}
int M = L + ((R - L) >> 1);
return process(arr, L, M) +
process(arr, M + 1, R) +
merge(arr, L, M, R);
}
public static int merge(int[] arr, int L, int M, int R) {
int[] help = new int[R - L + 1];
int i = 0;
int p1 = L;
int p2 = M + 1;
int res = 0;
while (p1 <= M && p2 <= R) {
if (arr[p1] > arr[p2]) {
res+= M - p1 + 1;
help[i++] = arr[p2++];
} else {
help[i++] = arr[p1++];
}
}
while (p2 <= R) {
help[i++] = arr[p2++];
}
while (p1 <= M) {
help[i++] = arr[p1++];
}
for (i = 0; i < help.length; i++) {
arr[L + i] = help[i];
}
return res;
}
}
3.2 数组小和
- 题目:每一个元素左边比当前元素值小的元素值累加起来
- 解法:每次归并的时候比较,左小右大产生小和
public class SmallSum {
public static int smallSum(int[] arr) {
if (arr == null || arr.length < 2) {
return 0;
}
return process(arr, 0, arr.length - 1);
}
public static int process(int[] arr, int l, int r) {
if (l == r) {
return 0;
}
int mid = l + ((r - l) >> 1);
return process(arr, l, mid) + process(arr, mid + 1, r) + merge(arr, l, mid, r);
}
public static int merge(int[] arr, int L, int M, int R) {
int[] help = new int[R - L + 1];
int i = 0;
int p1 = L;
int p2 = M + 1;
int res = 0;
while (p1 <= M && p2 <= R) {
res += arr[p1] < arr[p2] ? (R - p2 + 1) * arr[p1] : 0;
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= M) {
help[i++] = arr[p1++];
}
while (p2 <= R) {
help[i++] = arr[p2++];
}
for (i = 0; i < help.length; i++) {
arr[L + i] = help[i];
}
return res;
}
}