@TOC
总论
next_permutation、prev_permutation以及is_permutation均为全排列相关的函数,调用时需要加入头文件
#include < algorithm >
引入
next_permutation()
STL提供求下一个排列组合的函数next_permutation()。
next_permutation()函数是按照字典序产生排列的,并且是从数组中当前的字典序开始依次增大直至到最大字典序。
当已经是最后一次全排列的时候,函数会把传入的参数前后掉个个儿。
字符串的内部字典序排列(模仿):
bool next_str(string& str) {
const int len = str.length();
if (len <= 1) return false;
int left = -1, right = -1;
// 从后往前,找到第一个降序位置 left, 如 "2431" 中的位置 0,即 '2'
for (int i = len - 1; i > 0; --i)
if (str[i] > str[i - 1])
{
left = i - 1;
break;
}
// 如果没有找到,则已经是最后一个 permutation,返回 false
if (left == -1) return false;
// 从后往前,找到第一个比 str[left] 大的位置 right, 如 "2431" 中的位置 2, 即 '3'
for (int i = len - 1; i > left; --i)
if (str[i] > str[left])
{
right = i;
break;
}
// 交换 left 和 right
swap(str[left], str[right]);
// 从 left + 1 到最后,排序
sort(str.begin() + left + 1, str.end());
return true;
}
内部流程:
因为当完全降序的时候,直接返回 false,所以最后 str 保持完全降序结果。算法流程就是:
1、从后往前,找到第一个降序位置 left, 如 “2431” 中的位置 0,即 ‘2’
(如果没有找到,则已经是最后一个 permutation,返回 false)
2、从后往前,找到第一个比 str[left] 大的位置 right, 如 “2431” 中的位置 2, 即 ‘3’
3、交换 left 和 right 位置上的值
4、从 left + 1 到最后,排序
通过例子可以更好地理解:2431 -> 3124 -> 3142 。
计算 2431 的下一个排列的过程为:
1、从后往前,找到第一个将序位置,即 ‘2’ 的位置 0
2、从后往前,找到第一个比 ‘2’ 大的值 ‘3’ 的位置 2
3、交换 ‘2’ 和 ‘3’, 变成 3421
4、从位置 1 (0 + 1) 到最后,进行排序,变成 3124,即为结果。
函数原型:
template <class BidirectionalIterator>
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last );
template <class BidirectionalIterator, class Compare>
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last, Compare comp );
在使用next_permutation函数的时候切记要对全排列的对象进行升序排列,不然结果只会出现比当前排列大的排列,依据ASCII计算。
next_permutation()的一个实现
template<class BidirectionalIterator, class Compare>
bool next_permutation(BidirectionalIterator first, BidirectionalIterator last, Compare comp)
{
BidirectionalIterator front = last - 1;
BidirectionalIterator rear = last - 1;
bool found = false;
BidirectionalIterator i;
while (!found && front > first)
{
i = rear;
front--;
while(i>front)
{
if (comp(*front, *i))
{
found = true;
break;
}
else
i--;
}
}
if (found)
{
swap(*i, *front);
reverse(front + 1, last);
return true;
}
else
{
reverse(first, last);
return false;
}
}
int main()
{
string str = "1234";
int i = 1;
cout << i << ":" << str << endl;
while (next_permutation(str.begin(), str.end(), less<char>()))
{
i++;
cout << i << ":" << str << endl;
}
}
对于数字的排列:
next_permutation(a, b)表示只对[a, b)区间的数据进行全排列,其余位置不变化
需要先找到最小和最大值的引用。(所以下面我先sort()了一下)
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n,a[1000];
cin >> n;
for(int i = 0 ; i < n ; i++)
cin >> a[i];
sort(a,a + n);
do{
for(int i = 0 ; i < n ; i++)
cout << a[i] << " ";
cout << endl;
}while(next_permutation(a, a + n));
return 0;
}
prev_permutation
prev_permutation和next_permutation功能一样,唯一的区别是next_permutation下一个全排列,而prev_permutation是上一个全排列,所以运用prev_permutation的时候必须降序排列,不然只会出现比结果小的排列.
is_permutation
is_permutation用来判断两个全排列是否相等,哪怕顺序不同,只要元素一样就返回true。
函数原型:
template <class ForwardIterator1, class ForwardIterator2>
bool is_permutation (ForwardIterator1 first1, ForwardIterator1 last1,
ForwardIterator2 first2);
template <class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>
bool is_permutation (ForwardIterator1 first1, ForwardIterator1 last1,
ForwardIterator2 first2, BinaryPredicate pred);
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int> V1 = { 3, 4, 2, 1 };
vector<int> V2 = { 1, 3, 2, 4 };
vector<int> V3 = { 1, 3, 2, 4, 1};
vector<float> V4 = { 1.0, 3.0, 2.0, 4.0 };
vector<float> V5 = { 1.0000001, 3.0, 2.0, 4.0 };
if (is_permutation(V1.begin(), V1.end(), V2.begin()))
{
cout << "V1 and V2 is equal" << endl;
}
if (is_permutation(V1.begin(), V1.end(), V3.begin()))
{
cout << "V1 and V3 is equal" << endl;
}
if (is_permutation(V1.begin(), V1.end(), V4.begin()))
{
cout << "V1 and V4 is equal" << endl;
}
if (is_permutation(V1.begin(), V1.end(), V5.begin()))
{
cout << "V1 and V5 is equal" << endl;
}
return 0;
}
//result
/*
V1 and V2 is equal
V1 and V3 is equal
V1 and V4 is equal
*/