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

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. {1, 2, 3}
  2. {1, 3, 2}
  3. {2, 1, 3}
  4. {2, 3, 1}
  5. {3, 1, 2}
  6. {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 算法步骤
  1. 从右向左找到第一个升序对 (i, i+1),使得 a[i] < a[i+1]
  2. 如果找不到这样的对,说明已经是最大排列,返回 false
  3. 从右向左找到第一个大于 a[i] 的元素 a[j]
  4. 交换 a[i]a[j]
  5. i+1 到末尾的元素反转(变为升序)
5.2 图解示例

对于序列 {1, 3, 4, 2}

  1. 从右向左找:找到 3 < 4(位置 1 和 2)
  2. 从右向左找大于 3 的数:找到 4
  3. 交换 3 和 4:{1, 4, 3, 2}
  4. 反转 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. 竞赛技巧
  1. 排列枚举 :使用 next_permutation 可以简洁地枚举所有排列
  2. 状态判断:利用返回值判断是否还有下一个排列
  3. 组合排列 :与 sort 配合使用,确保从最小排列开始
  4. 剪枝优化:在排列生成过程中可以提前退出,减少计算量
总结

next_permutation 是 C++ STL 中一个非常强大且高效的工具,特别适合解决排列相关的问题。在信息学竞赛中,掌握它的使用可以大大简化代码,提高解题效率。关键是要记住:

  1. 根据题意判断是否需要先对序列排序

  2. 利用 do-while 循环生成所有排列

  3. 注意处理重复元素的情况

各种学习资料,助力大家一站式学习和提升!!!

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;
}
相关推荐
深盾科技3 小时前
融合C++与Python:兼顾开发效率与运行性能
java·c++·python
代码村新手3 小时前
C++-入门
开发语言·c++
神舟之光3 小时前
VSCode编译运行C/C++程序问题及解决方法
开发语言·c++
坐怀不乱杯魂3 小时前
C++ STL unordered_map/set 实现
开发语言·c++
hetao17338373 小时前
2025-12-21~22 hetao1733837的刷题笔记
c++·笔记·算法
呱呱巨基4 小时前
Linux 进程控制
linux·c++·笔记·学习
罗湖老棍子4 小时前
最小函数值(minval)(信息学奥赛一本通- P1370)
数据结构·c++·算法··优先队列·
肆悟先生4 小时前
3.17 内联函数
c++
仰泳的熊猫5 小时前
1109 Group Photo
数据结构·c++·算法·pat考试