使用next_permutation实现全排列
std::next_permutation 是 C++ STL 中
要使用 std::next_permutation 实现全排列,通常需要以下步骤:
对序列进行排序:这是非常重要的一步。std::next_permutation 从当前排列开始生成下一个字典序更大的排列。为了确保能生成 所有 的排列,你需要从字典序最小的排列开始,也就是排序后的序列。
使用 do-while 循环:
在循环体内部,首先处理(比如打印)当前的排列。
然后调用 std::next_permutation 来生成下一个排列。
循环条件是 std::next_permutation 的返回值。只要它返回 true(表示成功生成了下一个排列),就继续循环。
下面是一个使用 std::next_permutation 实现 std::vector<int> 和 std::string 全排列的示例:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // for std::sort and std::next_permutation
#include <iterator> // for std::ostream_iterator (optional for printing)
// 辅助函数:打印 vector 内容
template <typename T>
void print_sequence(const T& container, int& count) {
std::cout << ++count << ": ";
for (const auto& element : container) {
std::cout << element << " ";
}
std::cout << std::endl;
}
int main() {
// 示例 1: 对整数向量进行全排列
std::cout << "--- Permutations of a vector<int> ---" << std::endl;
std::vector<int> nums = {1, 2, 3};
int permutation_count_nums = 0;
// 1. 对序列进行排序 (对于 {1, 2, 3} 已经是排序好的,但这是好习惯)
std::sort(nums.begin(), nums.end());
// 2. 使用 do-while 循环生成并打印所有排列
std::cout << "Original sorted sequence: ";
for(int n : nums)
std::cout << n << " ";
std::cout << std::endl;
std::cout << "All permutations:" << std::endl;
do {
print_sequence(nums, permutation_count_nums);
} while (std::next_permutation(nums.begin(), nums.end()));
std::cout << "Total permutations for vector: " << permutation_count_nums << std::endl; // 应为 3! = 6
std::cout << "\n--- Permutations of a string ---" << std::endl;
// 示例 2: 对字符串进行全排列
std::string s = "abc";
int permutation_count_str = 0;
// 1. 对字符串进行排序 (对于 "abc" 已经是排序好的)
std::sort(s.begin(), s.end());
std::cout << "Original sorted string: " << s << std::endl;
std::cout << "All permutations:" << std::endl;
do {
print_sequence(s, permutation_count_str);
} while (std::next_permutation(s.begin(), s.end()));
std::cout << "Total permutations for string: " << permutation_count_str << std::endl; // 应为 3! = 6
std::cout << "\n--- Permutations with duplicate elements ---" << std::endl;
// 示例 3: 包含重复元素的向量
std::vector<int> nums_with_duplicates = {1, 1, 2};
int permutation_count_duplicates = 0;
std::sort(nums_with_duplicates.begin(), nums_with_duplicates.end());
std::cout << "Original sorted sequence with duplicates: ";
for(int n : nums_with_duplicates)
std::cout << n << " ";
std::cout << std::endl;
std::cout << "All unique permutations:" << std::endl;
do {
print_sequence(nums_with_duplicates, permutation_count_duplicates);
} while (std::next_permutation(nums_with_duplicates.begin(), nums_with_duplicates.end()));
// 对于 {1, 1, 2},唯一的排列是:
// 1 1 2
// 1 2 1
// 2 1 1
std::cout << "Total unique permutations for vector with duplicates: " << permutation_count_duplicates << std::endl; // 应为 3!/2! = 3
return 0;
}
代码解释:
#include <algorithm>: std::sort 和 std::next_permutation 都在这个头文件中定义。
std::sort(container.begin(), container.end()):
在调用 std::next_permutation 循环之前,我们首先对容器(vector 或 string)进行排序。
这是因为 std::next_permutation 生成的是字典序上的下一个排列。为了确保遍历所有可能的排列,必须从字典序最小的排列开始,即已排序的排列。
如果初始序列不是排序好的,你可能会错过一些排列,或者排列的顺序不是标准的字典序。
do { ... } while (std::next_permutation(container.begin(), container.end()));:我们使用 do-while 循环,是因为我们希望至少处理(打印)一次初始的(已排序的)排列。
- 循环体内部:
print_sequence(container, count): 在这里你可以对当前的排列进行任何你需要的操作,比如打印、存储、或者进一步处理。 - 循环条件:
std::next_permutation(container.begin(), container.end()): 这个函数尝试将 container 中的元素重新排列为其字典序上的下一个排列。
如果成功找到了下一个更大的排列,它会修改 container 并返回 true。
如果当前的排列已经是字典序最大的了(例如,对于 {3, 2, 1}),它会将 container 变成字典序最小的排列(即 {1, 2, 3}),并返回 false。这时循环终止。 - 处理重复元素:
std::next_permutation天然地能够正确处理包含重复元素的序列,并生成所有唯一的排列。例如,对于 {1, 1, 2},它会生成 112, 121, 211,而不会生成重复的排列。这是因为它基于字典序比较。
总结关键点:
- 必须先排序:确保从字典序最小的排列开始,以生成所有排列。
- do-while 循环:先处理当前排列,再生成下一个。
- 返回值:true 表示成功生成下一个排列,false 表示当前已是最大排列,循环结束。
- 原地修改:
std::next_permutation直接修改传入的容器。 - 处理重复元素:自动生成唯一的排列。
这种方法非常简洁且高效,是 C++ 中实现全排列的标准方式之一。

浙公网安备 33010602011771号