栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

全排列(无序+按字典序)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

全排列(无序+按字典序)

全排列

题目来源:open judge1750全排列

全排列 1.0

#include 
using namespace std;
void permutation(char a[],int m,int n){//对下标为m_n的字符数组段进行排列
	if(m==n){//安排好了最后一位 
		for(int i=0;i<=n;i++){
			cout<>str;
	int len=strlen(str);
	permutation(str,0,len-1);
	return 0;
}

这种交换不能按照字典序进行全排列,为什么呢?
注意题目要求,“给定的字符串中的字母已经按照从小到大的顺序排列”
想要达到目的,每个字符轮流做第一位确保得到所有组合情况,但却没能
确保除第一位以外,剩余的各位仍然按照从小到大的顺序排列
在数组中直接将某位移到第一位,对剩余字符的处理却是 将第一位直接抛到后面不知道某位,则此次排序直接不能保证升序 之前一直被两个swap函数迷惑住,以为换回来是为了保证有序的,并不是,换回来是为了得到全排列组合后回到原来的最初始的序列 进行另外的全排列。
全排列 的内容有序与否,是第一次交换后的结果,极限思维,更新第一位后排列得到的 //123 321
第一种组合都是 仅仅更新第一位的序列,直接无序了

全排列 2.0
受到以上思想的启发,想要达到目的——每个字符轮流做第一位确保得到所有组合情况,并确保除第一位以外,剩余的各位仍然按照从小到大的顺序排列 。”注意题目要求,“给定的字符串中的字母已经按照从小到大的顺序排列”,那么直接维持原有序列就好,将某位字符移到第一位,剩余字符保持原序,在数组小标1——n的位置放好。

#include 
using namespace std;
void swap1(char* a,int m,int i){//对下标为m_n的字符数组段进行排列,把a[i]提到首位m 
	char temp=a[i];
//	a[i]=a[i-1] 	a[i-1]=a[i-2] ……a[m+1]=a[m]  
	for(int j=i;j>=m+1;j--){
		a[j]=a[j-1];
	}
	a[m]=temp;
}
void swap2(char *a,int m,int i){
	char temp=a[m];
//	a[m]=a[m+1] 	a[m+1]=a[m+2] ……a[i-1]=a[i]  
	for(int j=m;j<=i-1;j++){
		a[j]=a[j+1];
	}
	a[i]=temp;
}
void permutation1(char a[],int m,int n){//对下标为m_n的字符数组段进行排列
	if(m==n){//安排好了最后一位 
		for(int i=0;i<=n;i++){
			cout<>str;
	int len=strlen(str);
	permutation1(str,0,len-1);
	return 0;
}
 

在写函数permutation1 的时候,又发现一个不清楚的问题,就是 想把子函数中数组的形参 声明为数组的引用。
数组的形参声明方式有:
(一)、chara
对于这种形式,老师以前上课讲过,用字符串地址的方式声明字符串,在内存中开了一个足够大的缓冲区。
用char
声明的是常量字符数组,所以之前用这种方式声明数组来做事总是出错。

当然啦,char*当作形参表示的是char a[]这个数组的地址,倒没有设计到main中数组的生命方式。
(二)、
想用数组的引用来声明形参,
奈何学识浅薄,涉及到了STL模板,此处应有表情包
C/C++对数组的引用
C++对数组的引用
C++对数组的引用(讨论的帖子)
之后再好好看看。

全排列 3.0
同思路2还有另一种实现方式,输出的序列用另一个数组存放,原数组元素从小到大排列的特性不去改变,只要利用这一点,从原数组中从前往后读取并存放在输出数组中,由于从前往后,输出数组读取到的元素一定是从小到大。

#include 
using namespace std;
char str[10];
char output[10];
int isvisited[10];//对原数组中的元素设置是否进行过访问的标志,因为从 
int len=0; 
void permutation3(int step){//分别确定output[step]的可能选取情况 
	if(step==len){//安排好了最后一位 
//		for(int i=0;i字符串嘛
return; 
	} 
	else{
		for(int i=0;i>str;
	len=strlen(str);
	permutation3(0);//对于output数组,从output[0]开始讨论每个元素可能的情况 
	return 0;
}
 
 

对于output数组,从output[0]开始讨论每个元素可能的情况
output[step]=str[i];//一种组合情况中确定好了 output[step],
接下来该选取 output[step+1],考虑到进入permutation3(step+1)后又是从str[0]
开始由小到大选一个 (这种形式就相当于利用递归来实现一个len重循环了)
,一种组合情况中不可能选两个相同的元素,故对之前选取过的元素
需要设置isvisited 标志 ,没访问过的才进行选择。在一种组合没有完成之前,
str中的元素isvisited标记会逐渐全部变为1,每次需要选标记为0且 下标最小的元素
直到一次组合完成,再从后往前回溯,逐一将访问标志恢复为0,为下一次组合做准备

全排列 4.0
利用已有的next_permutation函数
介绍:next_permutation函数将按字母表顺序生成给定序列的下一个较大的排列,直到整个序列为降序为止。注意添加头文件#include

使用方法:next_permutation(数组头地址,数组尾地址);
若下一个排列存在,则返回真,如果不存在则返回假
若求上一个排列,则用prev_permutation
next_permutation(str,str+strlen(str))
数组下标从0开始噢,全排列的部分是,str[0]到str[len-1]

#include 
using namespace std;
int main(int argc, char** argv) {
	char str[10];
	cin>>str;
	int len=strlen(str);
	for(int i=0;i 

至于next_permutation()的具体实现方式,参考以下(从别的大佬那儿搬来的):
STL具体操作之next_permutation和prev_permutation函数

#include
#include
using namespace std;

int a[12];

bool turn(int a[] ,int n)
{
    int k = n - 1; 
    while(a[k-1] > a[k]) k--;//找到位置k

    //当k的位置是0的时候,说明整个排列时递减的,这个排列的字典序最大
    if(k == 0) return false;//因此返回false

    k = k - 1;
    int t = n - 1;
    while(a[k] > a[t]) t--;//从后往前找到第一个大于a[k]的数字的位置 
    swap(a[k] , a[t]);//交换
    reverse(a + k + 1, a + n);//翻转

    return true;//返回true
}

int main()
{
    int n;
    cin>>n;

    for(int i = 0 ; i
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/312187.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号