题目1:给定两个排序后的数组A和B,其中A的末端有足够的缓存空间容纳B,编写一个方法将A并入B并排序
思路:两个有序的数组合并就是归并排序里面的归并步骤
题目2:一个数列,如果左边的数大,右边的数小,则称这两个数为一个逆序对,求一个数列中有多少个逆序对。
给定一个乱序数组arr
首先要知道:归并排序:
这两个有序数列竖着放了(方便理解)
对这两个有序的序列归并的时候 :如果左指针所指元素大于右指针所指元素,则说明左指针以下都大于右指针所指元素(右指针所指元素的逆序对个数就是mid-left+1).
知道了上面的情况过后,我们就可以求一个乱序的数组的逆序对了。例如上面的arr数组
我们知道归并排序通过递归来实现的,
在左侧递归的最底层是对8这一个元素合并(所以没有逆序对)
然后再往上一层【8】,【6】两个序列合并,然后是【6,8】,【7】这两个序列合并,得到有序子序列【6,7,8】
在右侧递归的最底层7一个元素合并,然后【7】与【3】合并得到【3,7】有序序列;然后【3,7】有序序列又与【5】合并得到【3,5,7】;
最后再将两个子序列合并。
所以我们通过再合并的时候统计以下当前左序列对于当前右序列元素的逆序对,所以说我们统计是从最开始左右子序列是同一个元素开始,到左右子序列都只有一个元素........所以尽管数组的顺序在慢慢改变,但是我们都是在改变之前统计了逆序对的。
代码:
package sort;
import java.util.Arrays;
import lanqiao.Swap;
public class 逆序对 {
public static int[] hleper;
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = {8,6,7,7,3,5};
int[] hleper = new int[arr.length];
mergsort(hleper,arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
System.out.println(nixu);
}
static int nixu = 0;//归并排序改动部分
public static void mergsort(int[] hleper,int[] arr,int p,int r) {
if(p<r) {
int mid = p+((r-p)>>1);
mergsort(hleper,arr,p,mid);
mergsort(hleper,arr,mid+1,r);
merge(hleper,arr,p,mid,r);
}
}
public static void merge(int[] hleper,int[] arr,int p,int mid,int r) {
Swap.Arraycopy(arr, hleper, p, r);
int left = p;
int right = mid+1;
int current = p;
while(left<=mid&&right<=r) {
if(hleper[left]<=hleper[right]) {
arr[current]=hleper[left];
left++;
current++;
}
else {
arr[current]=hleper[right];
right++;
current++;
nixu+=mid-left+1;//归并排序改动部分
}
}
//这里是有一边的元素全部遍历完了,我们需要把另外一边没遍历过的元素全部覆盖给原数组
while(left<=mid) {//左边没有遍历完的情况
arr[current]=hleper[left];
left++;
current++;
}
//右边没有遍历完的情况:因为开始的时候就复制了,所以不用去再覆盖一遍了
}
}