逆序数的求法

给定一组数据,求其中的逆序对的个数

方法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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值