全排列 by马昱春老师

全排列生成算法

递归法

普通递归,新加入的数字在中间穿梭
递归算法存在爆栈的问题
利用深度优先搜索DFS的递归方式。
1-n的排列的一一对应,存在一种顺序关系。
全排列与深度优先搜索:https://blog.csdn.net/u013238646/article/details/45417809

#include<stdio.h>
int n,a[10],book[10];//特别说明c语言全局变量没有赋值默认为 0,无需再次初始化; 
void dfs(int step)//step 表示当前在第几个位置 
{
	int i;
	if(step==n+1)//如果step==n+1表示前n个数字已经放好 
	{
		//输出一种全排列 
		for(i=1;i<=n;i++)
		 printf("%d",a[i]);
	    printf("\n");
	   return; 
	}
	//每次搜索都从1-n 一一尝试 
	for(i=1;i<=n;i++)
	{
		if(book[i]==0)//判断次数字是否用过 
		{
			a[step]=i;//存储当前位置的数字,以便满足条件输出 
			book[i]=1;//当前数字已用过,改变标志,以防重用 
			dfs(step+1);//放好当前位置数字之后,安排下一个数字 
			book[i]=0;//回溯,当满足一种全排列后,进行下一种尝试 
		}
	}
	return ;
}
int main()
{
	scanf("%d",&n);//输入只能为1-9之间的整数,表示1-n的全排列 
	dfs(1);//从第一个位置开始 
	return 0;
} 

字典序法

排列是有续的,除去最后一个排列中,都有前驱。除去第一个排列,都有后继。
所谓一个的下一个,就是这一个与下一个之间没有其他的。
一个字符串与下一个有尽可能长的共同前缀,也即变化尽可能限制在尽可能短的后缀上。这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
如果123的字典序全排列为:123 132 213 231 312 321
按字典序排列寻找下一个全排列的算法:由此非递归求出下一个全排列
从后往前扫描,如果一个序列从右向左都是增加的,就不存在下一个。如321
要找第一次出现下降的位置。要找到,比下降位置那个大的 中 最小的 那个换,交换完成以后再改变后缀的排列顺序使后缀字典序最小

SJT算法

全排列的生成
1234
数字具有移动的方向,每次交换相邻的数字,最大的能移动的数字发生交换。
4123—> 4132—> 132 4
可移动数:如果该数的方向 指向 的相邻数比概述小的话 则称该数是可移动数。1永远不可移动,n除了指向边界外都可以移动。
好处:模拟了递归的过程,但是不需要写递归
在这里插入图片描述

对于三种算法,虽然都是无重无漏,但是生成的顺序不相同。
对于算法的时间复杂度。复杂度很高。应为有n!个
递归的时间最快,但存在一定的内存风险。 根据需要进行修改。

问:如果不求所有全排列。
能否仅仅求出局部的序列。

83647521在字典序中是第几个排列:
77!+26!+45!+24!+33!+22!+1*1!
第一位数字有7654321七个都比他小,后面那些元素都是全排列7!
第二位数字 可选12 第三位数字可选 1245 系数为该位右边比他小的数字的个数(可以用的)。

什么叫做序号?
序号是先于此排列的排列的个数。

康托展开-字典序法

康托展开,利用阶乘表示数字。 康托集合论的奠基人。
中介数:序号与排列之间的一一对应的关系。中介数也就是康托展开的一种系数
中介数特点:记录第i位右边比当前数字小的数字个数,即记录了一种排列结构。
由中介数可以推导出排列

排列——序号——中介数 完全一一对应。
注意中介数的每一位 ki的最大值是n-i。序号是十进制数。
中介数并非一个等进制数。是一个递增进位制数法。
https://leetcode.com/problems/permutation-sequence/
https://leetcode.com/problems/next-permutation/
在这里插入图片描述
如何求康托展开的系数(即由序号转换为递增进制数)
逐一除去阶乘,取模。 模值就是进位值。
如何由序号转换为康托展开的系数需要回溯已经使用过的。

由此可知在字典序法中由中介数求排列比较麻烦,我们重新定义中介数。得到递增进位制数法

递增进位制数法

中介数的定义:ai记录数字i右边比i小的个数有多少个。
由递增进位制数法的中介数求排列:
先从高位开始放。(从大的那个数开始放下去)一次扫描就可以找到相应的位置
eg 839647521—849617523 是一个相邻的排列 邻域性质比较差

递减进位制数法

对于递增进制数,由于最低位进制太小,容易很频繁的进位。造成下一个排列与前一个排列之间的关联性没有那么紧密。 最低一位逢n进一。
递减进位制数法与递增进位制数法是一个翻转的关系。
在这里插入图片描述
递减进位制数,下一个排列有比较好的邻域性。更好地方法有邻位兑换法。
在进位不频繁,中介数不进位的情况下,只要把最大数和左边相邻数对换一下即可求得下一个排列。

如何求给定一个排列后面的某个排列:
由原排列求得原中介数,在通过递增递减进位制数法加减法求得新中介数,在转换为新排列。

组合的生成

排列是有序的,组合是无序的。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值