0

0

c++中如何使用std::prev_permutation生成上一个排列_c++算法技巧【实例】

穿越時空

穿越時空

发布时间:2026-01-18 08:27:09

|

146人浏览过

|

来源于php中文网

原创

std::prev_permutation 返回 false 且不修改序列,是因为当前序列已是字典序最小排列(如{1,2,3}),它仅生成前一个合法排列,不绕回最大排列。

c++中如何使用std::prev_permutation生成上一个排列_c++算法技巧【实例】

std::prev_permutation 为什么返回 false 却没变出上一个排列

根本原因:它只对「当前序列的字典序前一个排列」有效,且要求输入序列本身是某个排列的「合法中间态」。如果当前序列已是字典序最小(如 {1,2,3}),调用 std::prev_permutation 不会修改容器,直接返回 false

常见错误现象:

std::vector v = {1,2,3};
bool ok = std::prev_permutation(v.begin(), v.end()); // ok == false,v 仍是 {1,2,3}
这不是 bug,是设计行为——它不负责“绕回”到最大排列(比如 {3,2,1}),那得你自己处理。

  • 必须确保容器元素支持 比较,且已按升序/降序排好基础结构
  • 若想枚举全部排列(含“绕回”),应先用 std::sort 得到最大排列,再反复调用 prev_permutation
  • 它修改的是原容器,不是返回新排列;别误以为它像 Python 的 itertools.permutations 那样惰性生成

如何用 std::prev_permutation 枚举所有排列(从大到小)

关键步骤是「先排成最大字典序,再持续求前一个」。这和 next_permutation(从小到大)正好对称。

#include 
#include 
#include 

int main() {
    std::vector v = {1, 2, 3};
    
    // 第一步:升序 → 最大排列需先降序
    std::sort(v.begin(), v.end(), std::greater());
    
    do {
        for (int x : v) std::cout << x << ' ';
        std::cout << '\n';
    } while (std::prev_permutation(v.begin(), v.end()));
}

输出顺序是:3 2 13 1 22 3 12 1 31 3 21 2 3。注意最后一步后循环终止,prev_permutation 返回 false

  • 不能跳过 std::sort(..., std::greater) 这步,否则起点不对,漏排列
  • 循环条件必须是 while (prev_permutation(...)),不能写成 do...while 后再调一次——那样会多算一次失败状态
  • 自定义比较器必须严格弱序;若用 std::greater,确保元素类型支持 >

std::prev_permutation 和自定义类型配合要注意什么

核心是重载 operator 或传入二元谓词。它内部只做字典序比较,不关心语义。

立即学习C++免费学习笔记(深入)”;

例如对结构体排序:

Khroma
Khroma

AI调色盘生成工具

下载
struct Point {
    int x, y;
    bool operator<(const Point& other) const {
        return x != other.x ? x < other.x : y < other.y;
    }
};

然后这样用:

std::vector pts = {{2,1}, {1,3}, {1,2}};
std::sort(pts.begin(), pts.end()); // 先排成最大?不,先升序得到最小
// 若想从大到小枚举:先 std::sort(pts.rbegin(), pts.rend())
std::sort(pts.rbegin(), pts.rend()); // 等价于降序
do {
    // ...
} while (std::prev_permutation(pts.begin(), pts.end()));
  • 比较函数里不要有副作用(比如打印、修改全局变量)
  • 如果用 lambda 作谓词,必须捕获为空,且声明为 constexpr(C++20 起)或确保可内联,否则某些标准库实现可能编译失败
  • 浮点数慎用:因精度问题导致比较结果不稳定,prev_permutation 可能提前终止或死循环

性能与边界:为什么它比手写回溯快,但又不适合超长序列

时间复杂度是 O(n),单次调用平均只扫描常数次;而生成全排列的总复杂度仍是 O(n! × n),但它避免了递归栈开销和内存分配。

但实际使用中容易忽略两点:

  • 它依赖当前排列的「邻接性」:两个相邻排列在字典序中只差常数位置交换,所以不能跳着走(比如想直接从第 100 个跳到第 50 个,不行)
  • n > 12 时,n! 已超 4.7 亿,即使每次 O(1) 也撑不住;此时应考虑按需计算(如康托展开逆运算)而非枚举
  • 没有内置去重逻辑:若容器含重复元素(如 {1,1,2}),prev_permutation 仍会生成重复排列;要去重得先 std::unique 配合排序,或改用 std::set 缓存

真正难的从来不是调用这个函数,而是判断当前状态是否属于「可被 prev_permutation 处理的有效前驱」——它不报错,只沉默失败。

相关专题

更多
全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

78

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

96

2025.09.18

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

196

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

189

2025.07.04

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

204

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

190

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

47

2026.01.05

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

390

2023.07.18

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

43

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 6.9万人学习

C 教程
C 教程

共75课时 | 4.1万人学习

C++教程
C++教程

共115课时 | 12.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号