前言
菜鸟漫漫成长路第一部——归并排序。
归并排序
归并排序采用的是分治的思想。就是将我们的问题一步步分解,再一步步去合并。
治( •̀ ω •́ )y
首先我们假设有两个有序数组,那么我们怎么去合并他们呢?
(⊙﹏⊙)首先我们可以假设两个指针,p1,p2以及一个长度为两个有序数组之和的新数组。然后让他们分别指在这两个数组的第一个。好啦,我们的准备工作就做好啦~接下来我们就去比较p1 p2的大小,将小的那个数字放入到我们的新数组中,然后将指向这个数的指针后移一位,继续比较。一直重复重复,当有一个指针走完了整个数组,就将另一个数组剩下的全部放入到我们的新数组。嘻嘻,这样我们是不是就可以把两个有序数组合并成了一个新的有序数组呢( •̀ ω •́ )y。接下来看看一个很丑的图解!
分( •̀ ω •́ )y
问题就来了,要用上面的方法,我们必须是两个有序的数组呀。我们怎么去把一个无序的数组分成两个有序的数组呢?那么我们是不是可以用分解的办法呢。把一个数组分成两个,再将这两个数组分别分成两个…这样一直下去,直到分到我们的数组不能再分。然后再依次往上采用治的思想,咦,问题好像就解决了。( •̀ ω •́ )y。
code
使用递归的时候,我们递归之前的语句是顺序执行,递归之后的语句是逆序执行。因为我们的治是逆序的,所以应该放在递归语句后面。
public class MergeSort {
public static void mergeSort(int[] a){
if (a==null||a.length<2){
return;
}
mergeSort(a,0,a.length-1);
}
public static void mergeSort(int[] a,int l,int r){
if (l == r){
return;
}
int mid = l+((r-l)/2);
mergeSort(a,l,mid);
mergeSort(a,mid+1,r);
merge(a,l,r,mid);
}
private static void merge(int []a,int l,int r,int mid) {
int[] help = new int[r-l+1];
int i = 0;
int p1 = l;
int p2 = mid +1;
while(p1 <= mid && p2 <= r){
help[i++] = a[p1] < a[p2]? a[p1++] :a[p2++];
}
while(p1 <= mid){
help[i++] = a[p1++];
}
while(p2 <= r){
help[i++] = a[p2++];
}
for (int j = 0; j < help.length; j++) {
a[l+j] = help[j];
}
}
public static void main(String[] args) {
int[] a = {1,2,3,4,6,5,2,4,5,4};
mergeSort(a);
for (int i : a) {
System.out.print(i);
}
}
}
小和问题
在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
在治的过程中,修改一下其代码就好啦。
while(p1 <= mid && p2 <= r){
sum += a[p1] < a[p2]? a[p1]*(r-p2+1):0;
help[i++] = a[p1] < a[p2]? a[p1++] :a[p2++];
}
逆序对问题
在一个数组中,左边的数如果比右边的数大,则折两个数构成一个逆序对,请打印所有逆序对。
都是用分治的思想
public class MergeSort {
public static int mergeSort(int[] a){
if (a==null||a.length<2){
return 0;
}
return mergeSort(a,0,a.length-1);
}
public static int mergeSort(int[] a,int l,int r){
if (l == r){
return 0;
}
int mid = l+((r-l)/2);
return mergeSort(a,l,mid)+mergeSort(a,mid+1,r)+merge(a,l,r,mid);
}
private static int merge(int []a,int l,int r,int mid) {
int[] help = new int[r-l+1];
int i = 0;
int p1 = l;
int p2 = mid +1;
int sum = 0;
while(p1 <= mid && p2 <= r){
sum += a[p1] > a[p2]? (mid - p1 + 1):0;
help[i++] = a[p1] < a[p2]? a[p1++] :a[p2++];
}
while(p1 <= mid){
help[i++] = a[p1++];
}
while(p2 <= r){
help[i++] = a[p2++];
}
for (int j = 0; j < help.length; j++) {
a[l+j] = help[j];
}
return sum;
}
public static void main(String[] args) {
int[] a = {4,3,8,1};
System.out.print(mergeSort(a));
}
}