std::next_permutation要求输入为升序起始态,因其按字典序找下一个排列,若起始非升序(如"cba")则首次调用即返回false;正确做法是先sort再do-while循环。

next_permutation 为什么只对已排序序列有效
std::next_permutation 不是“生成所有排列”,而是“在当前排列基础上,按字典序找下一个”。它依赖当前状态——如果输入不是升序起始态(比如 "cba"),第一次调用就可能直接返回 false,后续排列全漏掉。常见错误是传入乱序字符串后反复调用,结果只输出一两个排列就停了。
正确做法是先用 std::sort 排好,再进循环:
std::string s = "bca";
std::sort(s.begin(), s.end()); // 变成 "abc"
do {
std::cout << s << "\n";
} while (std::next_permutation(s.begin(), s.end()));字符重复时 next_permutation 还能用吗
能,而且它天然去重。比如 "aab",std::next_permutation 生成的 3 个排列是:"aab"、"aba"、"baa",不会出现重复项。这是因为它内部比较逻辑基于“严格弱序”,遇到相同字符会跳过等价交换。
但注意:如果你手动实现或用其他库(比如 Python 的 itertools.permutations),默认不判重,必须额外套 set。C++ 标准库这点很省心。
立即学习“C++免费学习笔记(深入)”;
验证方式很简单:
std::string s = "aab";
std::sort(s.begin(), s.end());
int cnt = 0;
do { ++cnt; } while (std::next_permutation(s.begin(), s.end()));
// cnt == 3,不是 6next_permutation 对宽字符或自定义类型的支持
它不限于 std::string,只要迭代器指向的元素支持 operator<,就能用。比如 std::vector<wchar_t>、std::wstring,甚至 std::vector<int> 都可以:
-
std::next_permutation本质操作的是迭代器区间,和容器类型无关 - 中文 UTF-8 字符串不能直接用——因为一个汉字占多个
char,std::string按字节排,会把汉字拆开乱序;得先转成std::wstring或 Unicode 码点向量 - 自定义结构体需提供
operator<,且保证严格弱序(比如不能只比一个字段,忽略其他)
性能和边界要注意什么
全排列时间复杂度是 O(n!),std::next_permutation 单次调用均摊 O(1),但总循环仍是指数级。实际使用中容易卡死的点有:
- 对长度 ≥ 12 的字符串调用,排列数超 4.7 亿,基本跑不完
- 传入空字符串或单字符:
next_permutation返回false,循环体一次都不进,这是符合预期的 - 迭代器范围写错,比如用
s.begin()和s.end() - 1,会漏掉最后一个字符参与排列 - 多线程里共享同一字符串并调用
next_permutation?别这么做——它会原地修改,没锁就是数据竞争
真正要处理长序列的字典序枚举,得换思路:用回溯剪枝、或生成指定 rank 的排列(std::nth_element 不适用,得手写康托展开),而不是硬跑 next_permutation。


















