std::next_permutation生成字典序下一个排列,需先排序再用do-while循环遍历;对重复元素自动去重;支持自定义比较函数,但须满足严格弱序且与排序一致。

std::next_permutation 用来生成字典序下一个排列
它不生成全部排列,只把当前容器重排成字典序中紧挨着的下一个排列;如果已是最大排列(如降序),就重排为最小排列(升序)并返回 false。常见错误是以为调用一次就能拿到所有排列——其实必须在循环里反复调用,从初始升序开始才不会漏掉。
- 必须保证输入是“当前字典序下有效的起始状态”,通常先用
std::sort排成升序 - 对重复元素也有效,但会跳过重复排列(比如
{1,1,2}只产生 3 种而非 6 种) - 时间复杂度是 O(n),不是回溯式的指数开销,适合大数据量下的单次推进
怎么用 std::next_permutation 写全排列循环
核心是“先排序,再 do-while”。用 while 容易漏掉第一个排列,do-while 才能确保初始状态也被处理。
std::vector<int> v = {1, 2, 3};
std::sort(v.begin(), v.end());
do {
// 处理当前排列 v
} while (std::next_permutation(v.begin(), v.end()));
- 迭代器范围必须是
[first, last),别写成v.begin(), v.end() - 1 - 如果容器为空或只有一个元素,
std::next_permutation直接返回false,循环不执行 - 不要在循环体内修改容器大小(如
push_back),会破坏迭代器有效性
遇到 false 就停?那重复元素和自定义比较怎么办
返回 false 只表示“没有下一个字典序排列”,不代表出错。对含重复元素的序列,它天然去重;若要用自定义序(比如按绝对值排),必须传入第三个参数——比较函数对象。
- 自定义比较函数必须满足严格弱序,且和排序时用的完全一致,否则行为未定义
- 例如按字符串长度排:
std::next_permutation(v.begin(), v.end(), [](const auto& a, const auto& b) { return a.size() - 如果比较逻辑有副作用(比如打印日志),可能被多次调用,别依赖调用次数
为什么我的 vector 没变,或者结果乱序了
最常见原因是没初始化为升序,或者用了 std::array / 原生数组却传错了迭代器边界。另一个隐蔽坑是:迭代器失效发生在容器被移动(move)之后,但 std::next_permutation 不接管内存管理,它只操作已有元素。
立即学习“C++免费学习笔记(深入)”;
- 检查是否误用
std::next_permutation(v.begin(), v.begin() + v.size())—— 这和v.begin(), v.end()等价,但容易写错偏移 - 对
std::string直接用没问题:std::next_permutation(s.begin(), s.end()) - 如果元素类型没有
operator,编译失败,此时必须提供比较函数
真正麻烦的是当排列逻辑嵌套在多层作用域或 lambda 中,捕获方式影响变量生命周期——这时候 v 被提前析构,迭代器就指向野地址了。










