归并排序实质上是一种分治算法。
算法实质:
- 确定分界点,取数组中间位置mid
- 递归处理两边,分别进行排序 query(左)query(右)
- 将两边进行归并排序(合二为一)
算法时间复杂度:
O( nlog(n) ) (logn 层,每层遍历n个)
实际应用:
- 小和问题:
在随机元素,随机数组大小的数组中,找出左边比右边元素小的所有元素之和。
(归并排序是分段进行排序,在归并操作完成前,右边数组的所有数是一直保持在左边数组的右边。因此可以通过归并时判断大小时求解)
- 逆序对问题
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i] > a[j],则其为一个逆序对;否则不是。
给定一个长度为 n的整数数列,请你计算数列中的逆序对的数量。
同理。
代码:
import java.io.*;
class Main{
static int N = 100010;
static int n;
static int[] q = new int[N];
public static void main(String[] args) throws IOException{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(in.readLine());
String[] s = in.readLine().split(" ");
for(int i=0;i<n;i++)
q[i] = Integer.parseInt(s[i]);
query_sort(q,0,n-1);
for(int i=0;i<n;i++)
System.out.print(q[i]+" ");
}
public static void query_sort(int[] q,int l,int r){
if(l>=r) return;
// 确定分界点
int mid = l+r>>1;
// 递归处理两边数组
query_sort(q,l,mid);
query_sort(q,mid+1,r);
// 递归完后两边数组都是排好序的
// 归并
int i = l, j = mid+1, k=0;
int[] a = new int[r-l+1]; //取一个新数组,将比较后的值装在里面、
// 进行比较
while(i<=mid&&j<=r){
if(q[i]<=q[j])
a[k++] = q[i++];
else
a[k++] = q[j++];
}
// 将剩余的装入数组
while(i<=mid)
a[k++] = q[i++];
while(j<=r)
a[k++] = q[j++];
// 装回原数组
for(i=l,j=0;i<=r;i++){
q[i] = a[j++];
}
}
}