白话经典算法系列之九 从归并排序到数列的逆序数对(微软笔试题)

Posted heishanglaoyao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了白话经典算法系列之九 从归并排序到数列的逆序数对(微软笔试题)相关的知识,希望对你有一定的参考价值。

首先来看看原题

 

微软2010年笔试题

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

 

计算数列的逆序数对个数最简单的方便就最从前向后依次统计每个数字与它后面的数字是否能组成逆序数对。代码如下:

#include <stdio.h>
int main()
{
	printf("     数列的逆序数对 
");    
	printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --

");    

	const int MAXN = 8;
	int a[MAXN] = {1, 7, 2, 9, 6, 4, 5, 3};
	
	int nCount = 0;
	int i, j;
	for (i = 0; i < MAXN; i++)
		for (j = i + 1; j < MAXN; j++)
			if (a[i] > a[j])
				nCount++;

	printf("逆序数对为: %d
", nCount);
}

运行结果如下:

技术分享图片

这种方法用到了双循环,时间复杂度为O(N^2),是一个不太优雅的方法。因此我们尝试用其它方法来解决。

 

在《白话经典算法系列之五归并排序的实现》中观察归并排序——合并数列(135)(24)的时候:

1.先取出前面数列中的1

2.然后取出后面数列中的2明显!这个2和前面的35都可以组成逆序数对即3252都是逆序数对。

3.然后取出前面数列中的3

4.然后取出后面数列中的4同理,可知这个4和前面数列中的5可以组成一个逆序数对。

这样就完成了逆序数对的统计,归并排序的时间复杂度是O(N * LogN),因此这种从归并排序到数列的逆序数对的解法的时间复杂度同样是O(N * LogN),下面给出代码:

//从归并排序到数列的逆序数对
#include <stdio.h>
int g_nCount;
void mergearray(int a[], int first, int mid, int last, int temp[])
{
	int i = first, j = mid + 1;
	int m = mid,   n = last;
	int k = 0;

	while (i <= m && j <= n) //a[i] 前面的数  a[j] 后面的数
	{
		if (a[i] < a[j])
			temp[k++] = a[i++];
		else
		{
			temp[k++] = a[j++];
			//a[j]和前面每一个数都能组成逆序数对
			g_nCount += m - i + 1;
		}
	}

	while (i <= m)
		temp[k++] = a[i++];

	while (j <= n)
		temp[k++] = a[j++];

	for (i = 0; i < k; i++)
		a[first + i] = temp[i];
}
void mergesort(int a[], int first, int last, int temp[])
{
	if (first < last)
	{
		int mid = (first + last) / 2;
		mergesort(a, first, mid, temp);    //左边有序
		mergesort(a, mid + 1, last, temp); //右边有序
		mergearray(a, first, mid, last, temp); //再将二个有序数列合并
	}
}

bool MergeSort(int a[], int n)
{
	int *p = new int[n];
	if (p == NULL)
		return false;
	mergesort(a, 0, n - 1, p);
	return true;
}

int main()
{
	printf("     从归并排序到数列的逆序数对 
");    
	printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --

");    

	const int MAXN = 8;
	int a[MAXN] = {1, 7, 2, 9, 6, 4, 5, 3};

	g_nCount = 0;
	MergeSort(a, MAXN);
	printf("逆序数对为: %d
", g_nCount);
	return 0;
}

运行结果:

技术分享图片

 

 

好了,介绍到这里后,相信大家对如何求数列的逆序数对已经有了很好的认识,文章中所用到的“知识迁移”这种方法还是不错的,值得大家掌握。

 

 

转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/8029996

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://www.cnblogs.com/captainbed

以上是关于白话经典算法系列之九 从归并排序到数列的逆序数对(微软笔试题)的主要内容,如果未能解决你的问题,请参考以下文章

白话经典算法系列之五 归并排序的实现

白话经典算法系列之五 归并排序的实现

归并排序

归并和快速排序思想的延伸

转白话经典算法系列之七 堆与堆排序

白话经典算法系列之七 堆与堆排序