分治法求整数序列的逆序数

         在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数

      求逆序数的方法很多。最容易想到的办法是分别对序列中每一个元素求其逆序数,再求所有元素的逆序数总和,易分析得出这样的方法其时间复杂度为O(n2)。

      这里介绍一种分治的方法求逆序数,其思路如下。

       我们知道在对序列进行二路归并排序的时候,要将序列拆分成若干子序列,先将子序列排序,再合并子序列构成最终排序后的序列。二路归并算法还有一个特点,在进行归并操作时候的两个子序列是有序序列,所以,我们可以利用这一点,在归并子序列的时候,其中的子序列内部的逆序数必然是0,这时候能产生逆序数的情况必然处于子序列之间,即:“位置靠后的子序列”中的元素小于“位置靠前的子序列”的元素。例如,有子序列x:2,4,5;子序列y:1,3,6,显然,子序列y中的元素1的逆序数为3,子序列y中的元素3的逆序数为2,其他元素的逆序数均为0。通过这样一种方法,我们可以在序列的二路归并排序的过程中将序列的逆序数计算出来。故其时间复杂度为O(nlogn)。

      其代码实现如下:

     h1.h

#ifndef H1_H
#define H1_H

#include<string.h>
#include<ctype.h>
#include<malloc.h> /* malloc()等 */
#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<stdlib.h> /* atoi() */
#include<io.h> /* eof() */
#include<math.h> /* floor(),ceil(),abs() */
#include<process.h> /* exit() */

#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
/* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */


#endif
InversionCount.c

#include "h1.h"

int mergeCount(int a[], int low, int center, int high){

	int count;
	int i, j, k;

	if(low >= high){
		return 0;
	}

	int *temp = (int *)malloc(sizeof(int)*MAXSIZE);
	if(!temp){
		printf("Error!Memorry allocation wrong!");
	}

	count = 0;
	for(i=low,j=(center+1),k=0; i<=center&&j<=high; ){
		if(a[i]>a[j]){
			count += (center-i+1);
			temp[k++] = a[j++];
		}
		else{
			temp[k++] = a[i++];
		}
	}
	while(i <= center){
		temp[k++] = a[i++];
	}
	while(j <= high){
		temp[k++] = a[j++];
	}

	for(i=low; i<=high; i++){
		a[i] = temp[i-low];
	}

	free(temp);

	return count;
}

int inversionCount(int a[], int low, int high){

	int center;

	if(low < high){
		center = (low+high)/2;
		int rl, rr, r;
		rl = inversionCount(a, low, center);
		rr = inversionCount(a, center+1, high);
		r = mergeCount(a, low, center, high);
		return (rl+rr+r);
	}
	else{
		return 0;
	}
}

int main(){

	int a[] = { 12, 3, 7, 10, 14, 18, 19, 2, 11, 16, 17, 23, 25};

	int i, result=0;

	result = inversionCount(a, 1, 12);

	printf("The numbers sorted:\n");
	for(i=1; i<=12; i++){
		printf("%d  ", a[i]);
	}
	printf("\nThe inversion count is: %d\n", result);

	return 0;
}

注上述测试的序列为:
{3, 7, 10, 14, 18, 19, 2, 11, 16, 17, 23, 25}排在第一位的12表示元素个数,其最终逆序数为13.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值