cpfeed的专栏

计算技术改变生活

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

 闲来无事,复习复习经典的算法导论。看到了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 );

	}

}


 

 

 

阅读更多
文章标签: 算法 import class java
个人分类: 算法与数据结构
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭