csp信奥赛C++标准模板库STL(12):C++ STL 中的 next_permutation 详解

引言
next_permutation 是 C++ 标准库 <algorithm> 中的一个重要函数,用于生成序列的下一个字典序排列。它在信息学竞赛中非常有用,特别是在需要生成所有排列或找到下一个排列的问题中。接下来老师带领大家一起详细了解下next_permutation
1. 函数原型
cpp
template <class BidirectionalIterator>
bool next_permutation(BidirectionalIterator first, BidirectionalIterator last);
template <class BidirectionalIterator, class Compare>
bool next_permutation(BidirectionalIterator first, BidirectionalIterator last, Compare comp);
2. 基本功能
- 作用 :将范围
[first, last)中的元素重新排列为下一个字典序更大的排列 - 返回值 :
- 如果存在下一个排列,返回
true - 如果当前排列已经是最大排列(降序排列),返回
false,并将序列重置为最小排列(升序排列)
- 如果存在下一个排列,返回
3. 字典序排列
3.1 字典序概念
字典序就像单词在字典中的排列顺序:
- 比较两个序列时,从第一个元素开始
- 第一个不同的元素决定大小关系
- 例如:
{1, 2, 3}<{1, 3, 2}<{2, 1, 3}
3.2 排列示例
对于序列 {1, 2, 3},所有字典序排列为:
{1, 2, 3}{1, 3, 2}{2, 1, 3}{2, 3, 1}{3, 1, 2}{3, 2, 1}
4. 基本用法
4.1 生成下一个排列
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> nums = {1, 2, 3};
// 生成所有排列
do {
for (int num : nums) {
cout << num << " ";
}
cout << endl;
} while (next_permutation(nums.begin(), nums.end()));
return 0;
}
输出:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
4.2 检查是否有下一个排列
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> nums1 = {1, 2, 3};
vector<int> nums2 = {3, 2, 1};
cout << "nums1 has next: "
<< next_permutation(nums1.begin(), nums1.end())
<< endl;
cout << "nums2 has next: "
<< next_permutation(nums2.begin(), nums2.end())
<< endl;
return 0;
}
5. 算法原理
next_permutation 的实现基于以下步骤:
5.1 算法步骤
- 从右向左找到第一个升序对
(i, i+1),使得a[i] < a[i+1] - 如果找不到这样的对,说明已经是最大排列,返回
false - 从右向左找到第一个大于
a[i]的元素a[j] - 交换
a[i]和a[j] - 将
i+1到末尾的元素反转(变为升序)
5.2 图解示例
对于序列 {1, 3, 4, 2}:
- 从右向左找:找到
3 < 4(位置 1 和 2) - 从右向左找大于 3 的数:找到 4
- 交换 3 和 4:
{1, 4, 3, 2} - 反转 3, 2:
{1, 4, 2, 3}
6. 常见应用
6.1 生成全排列
cpp
#include <bits/stdc++.h>
using namespace std;
void generate_all_permutations(int n) {
vector<int> nums;
for (int i = 1; i <= n; i++) {
nums.push_back(i);
}
do {
for (int num : nums) {
cout << num << " ";
}
cout << endl;
} while (next_permutation(nums.begin(), nums.end()));
}
6.2 解决排列相关问题
cpp
#include <bits/stdc++.h>
using namespace std;
vector<int> kth_permutation(int n, int k) {
vector<int> nums;
for (int i = 1; i <= n; i++) {
nums.push_back(i);
}
for (int i = 1; i < k; i++) {
if (!next_permutation(nums.begin(), nums.end())) {
break;
}
}
return nums;
}
6.3 处理字符串排列
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
string str = "abc";
sort(str.begin(), str.end()); // 重要:必须先排序
do {
cout << str << endl;
} while (next_permutation(str.begin(), str.end()));
return 0;
}
7. 重要注意事项
7.1 结合排序使用
cpp
#include <bits/stdc++.h>
using namespace std;
// 错误示例:未排序直接使用
vector<int> nums = {3, 1, 2};
// 会从当前排列开始生成,可能不会生成所有排列
// 正确做法
sort(nums.begin(), nums.end());
do {
// 处理排列
} while (next_permutation(nums.begin(), nums.end()));
7.2 处理重复元素
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> nums = {1, 1, 2};
sort(nums.begin(), nums.end());
do {
for (int num : nums) {
cout << num << " ";
}
cout << endl;
} while (next_permutation(nums.begin(), nums.end()));
return 0;
}
输出(自动去重):
1 1 2
1 2 1
2 1 1
8. 时间复杂度与空间复杂度
- 时间复杂度:O(n),其中 n 是序列长度
- 空间复杂度:O(1),原地修改
9. 相关函数
9.1 prev_permutation
生成前一个字典序排列
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> nums = {3, 2, 1};
do {
for (int num : nums) {
cout << num << " ";
}
cout << endl;
} while (prev_permutation(nums.begin(), nums.end()));
return 0;
}
9.2 is_permutation
检查一个序列是否是另一个序列的排列
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {5, 4, 3, 2, 1};
if (is_permutation(v1.begin(), v1.end(), v2.begin())) {
cout << "v2 is a permutation of v1" << endl;
}
return 0;
}
10. 竞赛技巧
- 排列枚举 :使用
next_permutation可以简洁地枚举所有排列 - 状态判断:利用返回值判断是否还有下一个排列
- 组合排列 :与
sort配合使用,确保从最小排列开始 - 剪枝优化:在排列生成过程中可以提前退出,减少计算量
总结
next_permutation 是 C++ STL 中一个非常强大且高效的工具,特别适合解决排列相关的问题。在信息学竞赛中,掌握它的使用可以大大简化代码,提高解题效率。关键是要记住:
-
根据题意判断是否需要先对序列排序
-
利用 do-while 循环生成所有排列
-
注意处理重复元素的情况
各种学习资料,助力大家一站式学习和提升!!!
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"########## 一站式掌握信奥赛知识! ##########";
cout<<"############# 冲刺信奥赛拿奖! #############";
cout<<"###### 课程购买后永久学习,不受限制! ######";
return 0;
}
- 一、CSP信奥赛C++通关学习视频课:
- C++语法基础
- C++语法进阶
- C++算法
- C++数据结构
- CSP信奥赛数学
- CSP信奥赛STL
- 二、CSP信奥赛C++竞赛拿奖视频课:
- 信奥赛csp-j初赛高频考点解析
- CSP信奥赛C++复赛集训课(12大高频考点专题集训)
- 三、考级、竞赛刷题题单及题解:
- GESP C++考级真题题解
- CSP信奥赛C++初赛及复赛高频考点真题解析
- CSP信奥赛C++一等奖通关刷题题单及题解
详细内容:
1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):
https://edu.csdn.net/lecturer/7901 点击跳转



2、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

3、csp信奥赛冲刺一等奖有效刷题题解:
CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
- 2025 csp-j 复赛真题及答案解析(最新更新)
- 2025 csp-x(山东) 复赛真题及答案解析(最新更新)
- 2025 csp-x(河南) 复赛真题及答案解析(最新更新)
- 2025 csp-x(辽宁) 复赛真题及答案解析(最新更新)
- 2025 csp-x(江西) 复赛真题及答案解析(最新更新)
- 2025 csp-x(广西) 复赛真题及答案解析(最新更新)
- 2020 ~ 2024 csp 复赛真题题单及题解
- 2019 ~ 2022 csp-j 初赛高频考点真题分类解析
- 2021 ~ 2024 csp-s 初赛高频考点解析
- 2023 ~ 2024 csp-x (山东)初赛真题及答案解析
- 2024 csp-j 初赛真题及答案解析
- 2025 csp-j 初赛真题及答案解析(最新更新)
- 2025 csp-s 初赛真题及答案解析(最新更新)
- 2025 csp-x (山东)初赛真题及答案解析(最新更新)
- 2025 csp-x (江西)初赛真题及答案解析(最新更新)
- 2025 csp-x (辽宁)初赛真题及答案解析(最新更新)
CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转
- 129 道刷题练习和详细题解,涉及:模拟算法、数学思维、二分算法、 前缀和、差分、深搜、广搜、DP专题、 树和图
4、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转
· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}