算法导论学习1--分治法计算逆序数

原创 2011年09月06日 00:43:34

 闲来无事,复习复习经典的算法导论。看到了2-4,习题,计算逆序数的问题,忍不住实现了一下。

 

逆序数,是排列组合中常见的一个指标,可以用来衡量一个数列的杂乱成对(相对于顺序排列),在一些算法如水印算法中有广泛的应用。 如此如何快速的求得任意序列的逆

序数是关心的重点。常见的一种高效解法,是devid - and -conqure. 将序列平分成两段,分别计算逆序数,然后将两个有序的数列进行归并,并在归并过程中求取逆序数。两个

子序列的逆序数求取是较小规模的同样问题,可以用递归的方式完成。

 

简单说下如何在归并的过程中,计算逆序数。假设,有一个序列array[p, mid, r]. 其中array[p...mid], array[mid+1, ..., r]已经分别从小到大排好序。下面我们将两个子序列进行归

并。  假设当前的右边子序列(array[mid+1, ...., r])的当前待比较元素下表为right, 左边的为left, 当array[left] <= array[right], 这时候没有逆序发生(因为left的数 比right的

大)。当array[left] > array[right], 是,right指向的元素具有逆序数,个数为他之前的所有的数,即mid-left+1。如此遍历下去,即可得到在归并中得到逆序数。

 

算法非常简单直白。 复杂度为: T(n) = 2T(n/2) + O(n).  根据master定理, T(n) = O(nlogn). 空间复杂度为2n,当然可以更小,2logn。

 

附上java实现的源代码。

 

public class MergInversionCount {
	public static int count(int[] array, int p, int r) {
		int inversionCount = 0;
		if (p < r) {
			int mid = (p + r) / 2;
			inversionCount += count(array, p, mid);
			inversionCount += count(array, mid+1, r);
			inversionCount += mergeInversion(array, p, mid, r);
		}
		return inversionCount;
	}

	private static int mergeInversion(int[] array, int p, int mid, int r) {
		int inversionCount = 0;
		int[] temp = new int[r-p+1];
		if(array.length < r)
			return inversionCount;
		int left = p;
		int right = mid + 1;
		int storeIndex = 0;
		while(left <= mid && right <= r)
		{
			if(array[left] > array[right])
			{
				inversionCount += mid-left+1; //当前right存在逆序数,数目等于mid-left+1
				temp[storeIndex] = array[right];
				right++;
			}
			else
			{
				temp[storeIndex] = array[left];
				left++;
			}
			storeIndex++;
		}
		if(left <= mid)
		{
			for(int i = left; i <= mid; i++)
			{
				temp[storeIndex] = array[i];
				storeIndex++;
			}
		}
		if(right <= r)
		{
			for(int i = right; i <= r; i++)
			{
				temp[storeIndex] = array[i];
				storeIndex++;
			}
		}
		
		for(int i = p; i <= r; i++)
		{
			array[i] = temp[i-p];
			
		}
		return inversionCount;
	}

}



import static org.junit.Assert.*;

import org.junit.Test;

public class MergInversionCountTest {

	@Test
	public void testCount() {
		int[] array = {1,5,6,7,4};
		int[] array2 = {1,5,6,7,4,3,11, 15, 13, 2, 8};
		
		int inversionCount = MergInversionCount.count(array, 0, 4);
		assertTrue(inversionCount == 3 );
		
		inversionCount = MergInversionCount.count(array2, 4, 10);
		assertTrue(inversionCount == 10 );

	}

}


 

 

 

相关文章推荐

MIT算法导论学习笔记-Lecture4 分治法(续)

第四讲:分治法(续) 4.1 快速排序(Quicksort)

算法导论学习2.3 分治法 (这个递归终于懂了。。)

import java.util.Arrays; public class MergeSort { public static void main(String[] args) { ...

《算法导论》中的逆序数对问题

《算法导论》第三版中的逆序数对问题(习题2.4)

算法导论 归并排序解决逆序数

算法导论上对归并排序的算法描述如下 基本思想是将序列分成两部分 L R,然后合并,L R 是有序的算法的合并过程: Pseudocode: MERGE(A, p, q, r ) n1 ← q − p...

算法导论2.4 合并排序求逆序数

2-4 逆序对     设A[1...n]是一个包含n个不同数的数组。如果在iA[j],则(i,j)就称为A中的一个逆序对。     (1)列出数组{2,3,8,6,1}的五个逆序。     (...

算法导论第十四章习题14.1-7利用顺序统计数统计数组中的逆序数

所谓逆序对为对于数组a,如果ia[j],则这两个数即为一个逆序对。数组的逆序数即为数组中逆序对的个数。在第二章中的2-4利用合并排序的思路在O(nlgn)时间内统计数组a[n]的逆序数(具体方法可以参...

分治法求逆序数

  • 2013年02月02日 21:07
  • 948KB
  • 下载

[算法导论]分治法---最大子数组

分治策略---最大自子数组 一、分治策略的三个步骤 1、分解:将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小 2、解决:递归地求解出子问题。如果子问题的规模足够小...

算法导论-分治法-最近点对-HDOJ1007

HDOJ1007的原题目是求出在不同时套中两个玩具的前提下,圆圈的最大半径。问题翻译过来就是求解最近点对的问题,这个问题是经典的分治法问题。 参考博客:http://www.cnblogs.com/p...
  • jkhere
  • jkhere
  • 2014年03月20日 10:38
  • 3190

【算法导论】分治法及归并排序

有很多算法,在结构上他们是递归的:weile
  • Eaton18
  • Eaton18
  • 2014年09月18日 00:39
  • 352
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:算法导论学习1--分治法计算逆序数
举报原因:
原因补充:

(最多只允许输入30个字)