计算序列逆序数

最近在刷算法导论,在第二章思考题2-4的d问题,提示使用递归排序计算序列的逆序数。基本思想如下,归并排序的内容见我上一篇文章https://blog.csdn.net/weixin_44004576/article/details/102635900

递归每次将序列分解为左右两个序列,在合并的时候(此时假设左右序列都是完成排序,从小到大的顺序),如果左侧序列中的元素大于右侧序列中的元素,则意味着左侧序列剩余所有元素都对右侧序列指针目前所指向的元素构成逆序数对,因此在逆序数上加上目前左侧序列剩余元素的数量即可

算法导论的解释中如下图所示:下图为计算逆序数的整个计算框架
在这里插入图片描述下图为合并过程的计算框架:
在这里插入图片描述我做的改进仅仅是不使用哨兵,使用边界条件判断左右序列指针是否到达边界。(特别说明,我的代码中将p、q、r的顺序跟算法导论中的顺序是反的,贴算法导论的计算流程仅仅是图省事,懒得自己写流程,会在代码中注释)。另外由于排序的过程会导致如数序列的顺序被修改,所以在最终实现的时候采用适配器模式,将序列拷贝进去,修改的是新拷贝的变量,而不是原序列。

下面代码是适配器模式的逆序数计算器,核心是调用inversion_merge函数,需要注意的一点是p和q是需要计算序列中的所有边界索引数,从0开始计数,到size-1为止,所以在调用时,q应该设置成被计算序列长度减1:

template<typename T>
int inversion_cal(std::vector<T> input, int p, int q)
{
	int inversion_number = 0;

	inversion_number=inversion_merge<int>(input, p, q);

	return inversion_number;
}

下面是递归调用inversion_merge过程,里面主要是递归和和合并,相关解释参考我的上一篇文章:

template <typename T>
int inversion_merge(std::vector<T>& input,int p,int q)
{
	int inversion_number = 0;
	if (p < q)
	{
		int r = floor((p + q) / 2);
		inversion_number += inversion_merge(input, p, r);
		inversion_number += inversion_merge(input, r + 1, q);

		inversion_number += merge<int>(input, p, r, q);
	}

	return inversion_number;
}

最核心的部分就是合并不是计算逆序数,代码如下:

template<typename T>
int merge(std::vector<T> &input, int p, int r, int q)
{
	int n1 = r - p + 1;
	int n2 = q - r;

	int inversion_number = 0;

	std::vector<T> l_vector, r_vector;
	//copy data from origin array
	for (int i = 0; i < n1 + n2; i++)
	{
		if (i < n1)
			l_vector.push_back(input[p + i]);
		else
			r_vector.push_back(input[p + i]);
	}

	int i = 0;
	int j = 0;

	for (int k = 0; k <= q - p; k++)
	{
		if (i < n1 && j < n2)
		{
			if (l_vector[i] < r_vector[j])
			{
				input[p + k] = l_vector[i];
				i++;
			}
			else
			{
				input[p + k] = r_vector[j];
				inversion_number += (n1 - i); //当左侧序列指针所指大于右侧序列指针所指,将左侧序列所剩的所有元素的数量加到逆序数上即可
				j++;
			}
		}

		else if (i < n1 && j == n2)
		{
			input[p + k] = l_vector[i];
			i++;
		}

		else if (i == n1 && j < n2)
		{
			input[p + k] = r_vector[j];
			j++;
		}
		else if (n1 == 1 && n2 == 0)
		{
			input[p + k] = l_vector[0];
		}
	}

	return inversion_number;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章