按字典序输出数组的全排列

该博客介绍如何按照字典序输出1到n的全排列。通过定义next_permutation函数,利用升序查找、交换和逆序操作,逐步生成下一个排列。博主最初采用递归实现,但为避免栈溢出改用循环。文章提供了具体算法和代码示例。
Description

 输入一个数字n,输出从1~n组成的数字的全排列,每个排列占一行,输出按照数值升序排列

比如输入2,则输出是:

12

21

又如输入3,则输出是:

123

132

213

231

312

321

Input

 第一行是一个整数m,代表有m个测试用例

接下来的m行,每行是一个整数n,0 < n < 10

Output

 对于每个用例,输出它的全排列,每个排列占一行,输出按照数值升序排列


思路:

我定义了一个函数next_permutation来计算下一字典序,算法如下:

1)先从后往前找到一对升序组,设其坐标为a和a+1

2)从a+1到数组末尾找到一个大于a的最小的数,设其坐标为b

3)交换a和b位置的值<

生成 `n` 个数的全排列并按字典序输出,可以通过递归或使用标准库函数实现。以下分别介绍两种方法,并分析其原理。 ### 方法一:递归实现(深度优先搜索) 该方法通过回溯法遍历所有可能的排列合,并确保每个排列是唯一的。为了保证输出顺序为字典序,可以在构造排列时按照从小到大的顺序尝试数字。 ```cpp #include <iostream> using namespace std; int a[10]; // 存储当前排列 bool vis[10] = {0}; // 标记是否已使用该数字 void dfs(int x, const int& n) { if (x > n) { for (int i = 1; i <= n; i++) cout << a[i] << " "; cout << endl; return; } for (int i = 1; i <= n; i++) { if (!vis[i]) { a[x] = i; vis[i] = 1; dfs(x + 1, n); vis[i] = 0; } } } int main() { int n; cin >> n; dfs(1, n); return 0; } ``` 该算法利用递归和回溯的方式构建排列。在每一步中,从 `1` 到 `n` 按顺序选择未使用的数字插入当前位置,从而保证最终输出的排列是按字典序排列的 [^3]。 --- ### 方法二:使用 C++ 标准库函数 `next_permutation` C++ STL 提供了 `next_permutation` 函数,可以高效地生成下一个字典序排列。只需初始化一个升序数组,然后循环调用 `next_permutation` 即可生成所有排列。 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; i++) { a[i] = i + 1; } do { for (int num : a) cout << num << " "; cout << endl; } while (next_permutation(a.begin(), a.end())); return 0; } ``` 这种方法简洁高效,且 `next_permutation` 本身保证了排列按字典序生成 [^2]。 --- ### 原理分析 - **递归方式**:每次递归尝试将未使用的最小数字填入当前位置,从而保证排列生成的顺序自然符合字典序。 - **STL 方式**:`next_permutation` 内部实现基于“找到第一个可以增大的位置”,并通过交换与翻转操作生成下一个字典序排列。 --- ### 时间复杂度分析 - 全排列总数为 `n!`。 - 每种方法的时间复杂度均为 O(n!),但由于 `next_permutation` 是迭代实现,常数因子较小,在实际运行效率上通常优于递归方式。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值