给定一组数据,求其中的逆序对的个数
方法1:直接暴利法
两层循环,时间复杂度O(n^2)。
方法2:归并排序思想
这个时间复杂度是不尽如人意的,那有没有更好的方法呢?回想归并排序算法的过程,每次合并时,两部分都是已经排好序的,那么只需求出这两部分间的逆序对数再加上两个部分中各自的逆序对数即为合并后整个区间的逆序对数,如下两部分
[1, 3, 5] [2, 4, 6]
回想两部分的合并过程,比较1和2的大小,1较小,将1放入数组,之后比较3和2,3比2大,由于第一部分已经排好序,因此3之后的都与2形成逆序对,共2个逆序对,分别为(3, 2),(5, 2),依次下去,共3个逆序对
#include <stdio.h>
#include <stdlib.h>
int merge(int a[], int start, int middle, int end);
int mergesort(int a[], int start, int end);
int main()
{
int data[10] = {2,4,7,9,3,1,8,6,0,5};
int i;
for (i = 0; i < 10; i++) {
printf("%d ", data[i]);
}
printf("\n");
int ni = mergesort(data, 0, 9);
for (i = 0; i < 10; i++) {
printf("%d ", data[i]);
}
printf("\n");
printf("%d\n", ni);
return 0;
}
int merge(int a[], int start, int middle, int end)
{
int num = 0;
int n1 = middle - start + 1;
int n2 = end - middle;
int left[n1];
int right[n2];
int i;
for (i = 0; i < n1; i++) {
left[i] = a[start + i];
}
for (i = 0; i < n2; i++) {
right[i] = a[middle + i + 1];
}
int k = 0;
int k1 = 0, k2 = 0;
while (k1 < n1 && k2 < n2) {
if (left[k1] < right[k2]) {
a[start + k] = left[k1];
k1++;
k++;
} else {
a[start + k] = right[k2];
k2++;
k++;
num += n1 - k1;
}
}
while (k1 < n1) {
a[start + k] = left[k1];
k1++;
k++;
}
while (k2 < n2) {
a[start + k] = right[k2];
k2++;
k++;
}
return num;
}
int mergesort(int a[], int start, int end)
{
if (start < end) {
int middle = (start + end)/2;
int x, y, z;
x = mergesort(a, start, middle);
y = mergesort(a, middle + 1, end);
z = merge(a, start, middle, end);
return x + y + z;
}
return 0;
}