【scau算法分析设计】17086字典的全排序(c、STL的next_permutation())

本文主要介绍了如何使用C++ STL中的next_permutation函数生成一个字符串的字典序排列。通过输入字符串的长度和内容,程序将输出所有可能的字典序排列。文章详细解释了next_permutation函数的工作原理,并提供了两种实现方法,一种是直接使用STL,另一种是自定义算法。示例代码展示了如何应用这种方法生成特定输入的字典序排列及其后续排列。
摘要由CSDN通过智能技术生成

目录

一、 题目

Description

输入格式

输出格式

输入样例

输出样例

提示

二、 思路

三、代码

结果:


一、 题目

Description

什么叫字典序,顾名思义就是按照字典的排列顺序。
以字典序为基础,我们可以得出任意两个数字串的大小。比如 "1" < "12"<"13"。 就是按每个数字位逐个比较的结果。
对于一个数字串的排列,可以知道最小的排列是从小到大的有序串“123456789”,而最大的排列串是从大到小的有序串
“987654321”。这样对于“123456789”的所有排列,将他们排序,即可以得到按照字典序排序的所有排列的有序集合。

因此,当我们知道当前的排列时,要获取下一个排列时,就可以找到有序集合中的下一个数(恰好比它大的)。比如,
当前的排列时“123456879”,那么恰好比它大的下一个排列就是“123456897”。 当目前的排列是最大的时候,说明
所有的排列都找完了。

输入格式

请输入字串的长度n和字符串。(n<10)

注意:
(1)字符串不含重复元素。
(2)这里初始输入的字串不一定是排列的有序集合中最小的那个,即使不是最小的那个,输出也一定要按照从小
到大的顺序输出。

输出格式

字典序的每个排列,按序号输出。

输入样例

3
214

输出样例

1 124
2 142
3 214
4 241
5 412
6 421

提示

这里两个办法来输出字典序的所有排列。

方法一:
C++的STL真是个可以偷懒的好东西,用STL的next_permutation()函数,标准库全排列next_permutation()的返回值:
  bool类型。
假设数列:d1d2d3d4…… 范围由[first,last)标记,调用next_permutation使数列
逐次增大,这个递增过程按照字典序。

C++ Reference中next_permutation的函数声明如下:
#include <algorithm>
bool next_permutation( iterator start, iterator end );
The next_permutation() function attempts to transform the given range
of elements [start,end) into the next lexicographically greater permutation
of elements. If it succeeds, it returns true, otherwise, it returns false.

所以,将输入的数字序列用sort()或qsort()排下序,先找到最小的字典序排列,然后不断
调用next_permutation() 并输出,直至最后最大的一个。


方法二:思路同方法一,但自行编写计算一个当前字符串的下一个字典序排列。
设P是一个排列串:P = s[1]s[2]...s[n] = s[1]...s[j]...s[k]...s[n]

1)从当前排列串的右端开始,找出第一个比右边数字小的数字的序号j
(j从左端开始计算),即 j=max{ i |s[i]<s[i+1]};

2)在s[j]的右边的数字中,找出所有比s[j]大的数中最小的数字s[k],
即 k = max{ i |s[i]>s[j]}
(对s[j]右边数来说,从右至左是递增的,因此k是所有大于s[j]的数字中序号最大者,
序号虽最大但s[k]是处于s[j]右边且比s[j]大的数中的最小者);

3)交换s[j]和s[k];

4)再将s[j+1]...s[k-1]s[k]s[k+1]...s[n]倒转得到排列
 P' = s[1]s[2]...s[j] s[n]...s[k+1]s[k]s[k-1]...s[j+1],
这里P'就是排列P的下一个排列。

简单来说,就是对于给定的一个数,首先从右边找到第一个相邻“有序对”(这个“有序对”
的定义是就是满足s[i]<s[i+1]最右边对)。
现假设下一个要找的数比这个数大,且中间没有一个数比前者大、比后者小。然后再重新从
右边起找出第一个比那个"有序对"的较小者要大的数,交换他们,再将那个较小数下标后面的
子数组反转。

总结一下:就是由后向前找替换数和替换点,然后由后向前找第一个比替换数大的数与替换数
交换,最后颠倒替换点后的所有数据。

例如,如何得到 346987521 的下一个字典序排列?
1)从尾部往前找第一个s(i-1) < s(i)的位置:
  ... 4 6 < 9 < 8 < 7 < 5 < 2 < 1
  最终找到6是第一个变小的数字,记录下6的位置为i-1。
2)从i位置往后找到最后一个大于6的数。
  ... 4 6 > 9 > 8 > 7 5 2 1
  最终找到7的位置,记录位置为k。
3)交换位置i-1和k的值:   4 7 9 8 6 5 2 1
4)倒序i位置后的所有数据:4 7 1 2 5 6 8 9
  则347125689为346987521的下一个排列。 

二、 思路

采用方法一。

排序sort() + STL的next_permutation()

#include <algorithm>
bool next_permutation( iterator start, iterator end );
The next_permutation() function attempts to transform the given range
of elements [start,end) into the next lexicographically greater permutation
of elements. If it succeeds, it returns true, otherwise, it returns false. 

可参考: next_permutation(a,a+n)_如梦山河的博客-CSDN博客_next_permutation早就听说了了next_permutation 产生全排列的强大,一直到昨晚遇到一个对字符串产生全排列的问题才知道这个函数的强大,我们队是按照dfs去搞全排列,然后在进行字符串的匹配,结果写的很长,过程中还各种debug。。。于是决定今天学一下…next_permutation函数组合数学中经常用到排列,这里介绍一个计算序列全排列的函数:next_permutation(start,end),和...https://blog.csdn.net/qq_43488547/article/details/100032724?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163370619216780262514222%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163370619216780262514222&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-100032724.first_rank_v2_pc_rank_v29&utm_term=next_permutation&spm=1018.2226.3001.4187

三、代码

#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;

int main()
{
    int n;
    scanf("%d\n",&n);
    char ch[n];
    for(int i=0; i<n; i++)
        ch[i] = getchar();
    for(int i=0; i<n; i++){
        for(int j=0; j<n-i-1; j++){
            if(ch[j]>ch[j+1]){
                char c = ch[j];
                ch[j] = ch[j+1];
                ch[j+1] = c;
            }
        }
    }
    int p=1;
    do{
        printf("%d ",p++);
        for(int i=0; i<n; i++){
        cout<<ch[i];
        }cout<<endl;
    }while(next_permutation(ch,ch+n));

}

结果:

输入:
3
521

输出:
1 125
2 152
3 215
4 251
5 512
6 521
输入:
4
8532
输出:
1 2358
2 2385
3 2538
4 2583
5 2835
6 2853
7 3258
8 3285
9 3528
10 3582
11 3825
12 3852
13 5238
14 5283
15 5328
16 5382
17 5823
18 5832
19 8235
20 8253
21 8325
22 8352
23 8523
24 8532

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值