C++全排列的实现方法

法一:使用next permutation

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
    vector<char> seq;
    string s;
    cin>>s;
    seq.assign(s.begin(),s.end());
    sort(seq.begin(),seq.end());
    do{
    for(int i=0;i<seq.size();i++)
    {
        cout<<seq[i];
    }
    cout<<endl;
    }while(next_permutation(seq.begin(),seq.end()));
    return 0;
}

法二:使用简单DFS

在后面的代码中函数dfs的层数k代表着某一排列中的k个选择(一个排列中的第k个数字),具体机理类似下图(这个图也是理解递归的关键)
在这里插入图片描述

#include<iostream>
#include<vector>
#include<algorithm>
#include<string.h>
#include<stack>
#include<queue>
using namespace std;
int v[20]={0};//是否被访问
char res[20];
void dfs(int x,char *s,int n)
{
    
    int i;
    if(x==n+1)//dfs层数
    {
        for(i=0;i<n;i++) cout<<res[i];
        cout<<endl;
        
    }
    else
    for(i=0;i<n;i++)//递归思想理解
    {
        if(!v[i]){
            v[i]=1;//表示访问过了
            res[x-1]=s[i];
            dfs(x+1,s,n);
            v[i]=0;//每个排列之后对访问状态重置
            }
        
    }
}
int main()
{
    string s0;
    cin>>s0;
    char s[20]; 
    for(int i=0;i<s0.length();i++)
    {
        s[i]=s0[i];
    }
    sort(s,s+s0.length());//sort要到/0,表示s的尾部
    dfs(1,s,s0.length());
    return 0;
}

当然,该种方法使用了过多的堆栈,有更优化的方法。

另外一种dfs方法可以参照这篇博文
https://blog.csdn.net/qq_40742428/article/details/99436764
使用了回溯的方法

法三:使用字典序法

字典序法其实就是C++的nextpermutation的实现机理。
生成给定全排列的下一个排列:
所谓一个的下一个就是这一个与下一个之间没有其他的。这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
于是可以有下面计算下一个排列的算法:
1)简洁版
对于给定的一个数,首先从右边找到第一个相邻"逆序对",现假设下一个要找的数比这个数大,且中间没有一个数比前者大、比后者小。那么这个"逆序对"的定义是就是满足num[ i ]< num[ i+ 1 ](假设这个整数是以数组的形式存储的),然后再重新从右边起找出第一个比那个"逆序对"的较小者 要大的数,交换他们,再将那个较小数下标后面的子数组反转
2)严谨版
设P是1~n的一个全排列:p=p1p2…pn=p1p2…pj-1pjpj+1…pk-1pkpk+1…pn
  1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即 j=max{i|pi<pi+1}
  2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即 k=max{i|pi>pj}(右边的数从右至左是递增的,因此k是所有大于pj的数字中序号最大者)
  3)对换pi,pk
  4)再将pj+1…pk-1pkpk+1…pn倒转得到排列p’=p1p2…pj-1pjpn…pk+1pkpk-1…pj+1,这就是排列p的下一个排列。
在这里插入图片描述代码实现

	/**
	 * get the next permutation based on dictionary order method
	 * 
	 * @param cur
	 * @return next permutation string, or null if cur is the last
	 */
	public static String next(String cur) {
		String ret = null;
		if (cur == null)
			return ret;
		int strlen = cur.length();
		char[] lcur = cur.toLowerCase().toCharArray();
		int j = strlen - 2;
		while (j >= 0 && lcur[j] > lcur[j + 1]) {
			j--;
		}
		if (j < 0)
			return ret;
 
		int k = strlen - 1;
		while (lcur[k] < lcur[j]) {
			k--;
		}
 
		// swap lcur[k], lcur[j]
		char temp = lcur[k];
		lcur[k] = lcur[j];
		lcur[j] = temp;
 
		// reverse lcur[j+1, ..., strlen-1]
		int low = j + 1;
		int high = strlen - 1;
		while (low < high) {
			temp = lcur[low];
			lcur[low] = lcur[high];
			lcur[high] = temp;
			low++;
			high--;
		}
		ret = String.valueOf(lcur);
		return ret;
	}

最后这一部分来自于摘录和转载。不断学习,共同进步。敬请期待。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值