归并排序之逆序对数

微软2010年笔试题

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序数对。一个排列中逆序的总数就称为这个排列的逆序数。如{2,4,3,1}中,2和1,4和3,4和1,3和1是逆序数对,因此整个数组的逆序数对个数为4,现在给定一数组,要求统计出该数组的逆序数对个数。


这个题目是我在别人的csdn上看到的,没有想到微软也会出这样的题目,准确的是说在刘汝佳的算法入门经典中这是一道菜鸟题目,我记得我有一次比赛中还碰到这个题目了,那个时候直接把刘汝佳的代码copy一下,直接就AC了,之后那次比赛还每个人得了100¥,我用了两个小时就把100¥全部消耗殆尽,现在想一想我都不知道如何做的了,实在是可惜啊。


现在在把所有做过的题目都复习一下,以后怕问到,我知道题目,不知道如果做,现在越来越不如以前了,想一想以前刷题的日子,实在对自己失望。


首先是写出归并排序的代码由于本题要在归并排序之上改变一下,所以要借助归并排序。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

void Merge_sort (int *arr, int *temp, int x, int y) {
	if (y - x > 1) {
		int m = x + (y-x)/2;
		int q = x, p = m;
		int i = x;
		Merge_sort (arr, temp, x, m);
		Merge_sort (arr, temp, m, y);
		while (q < m || p < y) {
			if (p >= y || (q < m && arr[q] < arr[p])) temp[i++] = arr[q++];
			else temp[i++] = arr[p++];
		}
		
		for (int i = x;i < y;i++) {
			arr[i] = temp[i];
		}
	}
}

int main (void) {
	int num;
	int arr[100];
	int temp[100];
	while (scanf ("%d", &num) != EOF) {
		for (int i = 0;i < num;i++){
			scanf ("%d", &arr[i]);
		}
	
		Merge_sort (arr, temp, 0, num);
	
		for (int i = 0;i < num;i++) {
			printf ("%d ", arr[i]);
		}
		printf ("\n");
	}	
}

求逆序对数就是在上面的归并中改变一下就能求出了。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

int Cnt;

void Merge_sort (int *arr, int *temp, int x, int y) {
	if (y - x > 1) {
		int m = x + (y-x)/2;
		int p = x,q = m;
		int i = x;
		Merge_sort (arr, temp, x, m);
		Merge_sort (arr, temp, m, y);
		
		while (q < m || p < y) {
			if (p >= y || (q < m && arr[q] < arr[p])) temp[i++] = arr[q++];
			else {temp[i++] = arr[p++]; Cnt += m-p;}
		}
		for (int i = x;i < y;i++) {
			arr[i] = temp[i];
		}
	}
}

int main (void) {
	int num;
	int arr[100];
	int temp[100];
	while (scanf ("%d", &num) != EOF) {
		for (int i = 0;i < num;i++) {
			scanf ("%d", &arr[i]);
		}
		Cnt = 0;
		Merge_sort (arr, temp, 0, num);
		
		printf ("Cnt = %d", Cnt);
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值