全排列及相关扩展算法(五)——递增(递减)进位制数求原排列算法

49 篇文章 7 订阅

1.引入原因:通过上一章我们意识到通过原始中介数求原排列并不是那么的方便,于是我们延伸出几种新的中介数算法来方便计算原排列。

2.递增进位制数法:递增进位制是指数字的进制随着数字位置的不同递增,一般的,最右位的进制为2,向左依次增1。用递增进位制数法改造的中介数即:我们不按照从左到右的顺序排,而是按照数字的大小来排。以上一章{ 7,6,8,3,4,5,1,2 }为例,其原始中介数为{6,5,5,2,2,2,0,(0)},(原中介数由于最后一位恒等于0所以一直忽略不计,这里再加上)将其按照原来位上数字的大小排序变成新的中介数为:{5, 6, 5, 2, 2, 2, 0, 0},不难理解,每一个位上的数都不会超过其位数(因为其位取决于其真实数,而其值取决于其中介数),故称其为递增进位制数。

求递增进位制数代码:

int* get_permutation_medium_plus(int A[], int n)
{
	int* temp = new int[n];

	for (int i = 0; i < n; i++)
	{
		temp[n-A[i]] = 0;
		for (int j = i + 1; j <= n - 1; j++)
		{
			if (A[j] < A[i])
			{
				temp[n-A[i]]++;
			}
		}
	}

	return temp;
}
文末参考文档中有提到这种递增进位中介数通过下述算法求出一种序号,但不是字典序, 不是字典序!

int get_permutation_rank_plus(int medium[], int n)
{
	int rank = 0;
	for (int i = 0; i < n-1; i++)
	{
		rank += medium[i];
		rank *= n - i -1;
	}

	return rank;
}


其实就是转化成进制为位数n*k[n-1]的数,转化后每个位的进制变成0(0)、1(1)、2(1*2)、6(2*3)、24(6*4)、120(24*5)……


外部调用:

int A[] = { 4,3,2,1 };
	int n = sizeof(A) / sizeof(A[0]);
	//用STL模版函数遍历
	while (next_permutation(A, n)||!Count)
	{
		printf("原排列:  ");
		Print(A, n);
		printf("中介数:  ");
		int *medium = get_permutation_medium_plus(A, n);
		Print(medium, n);
		int rank = get_permutation_rank_plus(medium, n);
		printf("新序号:  %d\n", rank);
		printf("---------------\n");
		Count++;
	}


然而看起来并没有什么卵用



通过这种中介数求原排列非常的简便,中介数k[i]表示真实数n-i处于从右往左数第i个(之前已经存在的数不算),我们称此为空格法。

例如求342221的原排列

①__ __ ____ __ __ __第7位数字是3,我们从右向左数3个空格,再往前数一个空格,空格中填入对应的位数7。

②__ __ __7 __ __ __。第6位数字是4,我们从右向左数4个空格,其中已经放上数的不算空格,再往前数一个空格,空格中填入6。

③__ 6 __7 __ __ __。接下来的步骤也是一样的,第5位的数字是2,数2个空格,再往前数一个空格填入5。

④__ 6 __7 5 __ __。第4位是2,数2个空格再往前数一个空格填入4。

⑤__ 6 4 7 5 __ __。第3位是2,数2个空格再往前数一个空格填入3。

⑥3 6 4 7 5 __ __。第2位是1,数1个空格,再往前数一个空格填入2。

⑦3 6 4 7 5 2 __。第1位是0,数0个空格,再往前数一个空格填入1。

由此,我们得到了原来的排列3 6 4 7 5 2 1。

代码:

int* get_permutation_plus(int medium[], int n)
{
	int* temp = new int[n];
	memset(temp, 0, n * sizeof(int));
	for (int i = 0; i < n; i++)
	{
		int empty = -1,j=n;//防止末尾已经被占的情况故提前一位
		while (empty < medium[i] && j >= 0)
		{
			j--;
			if (temp[j] <= 0)
			{
				empty++;
			}
		}
		temp[j] = n - i;
	}

	return temp;
}





3.递减进位制数法:

考虑到递增进制法中低位的进制都比较低,在求下一个排列时,中介数加1往往会导致很多的进位,计算比较麻烦,所以有了递减进位,实际上就是将递增进位制的中介数倒过来即可。这使得通过遍历递减进位制法的中介数得到全排列算法,相比于用递增进位制法较简单。


4.参考文档

https://wenku.baidu.com/view/8c79a2facc17552706220880.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值