旋转法:
对于含有n个元素的数组,旋转n次之后他就会恢复原状。
选择法
假如给定的集合是ABC,那么我们可以先想一下最终的结果形式可以认为是所有以A开头,以B开头和以C开头的三种。按此递归的继续下去。
以A开头的,后面还有BC,接下来的第二个字符分为两种,以B开头的和以C开头的。那么结果就是ABC,ACB
以B开头的, 结果就是BAC和BCA
以C开头的, 结果是CAB和CBA
字典顺序
设有排列2763541,按照字典序排列,它的下一个排列是谁?
(1) 2763541 [找最后一个正序35]
(2) 2763541 [找3后面比3大的最后一个数4]
(3) 2764531 [交换3,4的位置]
(4) 2764135 [把4后面的531反序排列为135]
< header>
#include<iostream>
#include<algorithm>
#include<iterator>
#include<vector>
using namespace std;
< common used func >
void createArray(vector<int> *array, int const & n){
for (int i(1); i <= n; i++){
(*array)[i - 1] = i;
}
}
< 旋转法 >
//对容器中的前n个数进行旋转。
void rotate(int const &n, vector<int>*before, vector<int>*after){
copy(before->begin(), before->begin()+n-1, after->begin() + 1);
(*after)[0] = (*before)[n-1];
}
void permutation_v1_Helper(vector<int> *set, int const &n, vector<vector<int>> &result){
if (n == 1){//长度为1,不再旋转。
result.push_back(*set);
return;
}
permutation_v1_Helper(set, n - 1, result);//对set的前n-1个继续旋转。
vector<int> *temp1,*temp2;
temp1 = set;
for (int i(1); i < n; i++){//旋转n次就会回到原状,所以对set一共旋转n-1次
temp2 = new vector<int>(*temp1);
rotate(n, temp1, temp2);
temp1 = temp2;
permutation_v1_Helper(temp1, n - 1, result);//对旋转之后的容器的前n-1个数继续旋转
}
}
void permutation_v1(int const &n, vector<vector<int>> &result){
//生成数组
vector<int> *temp = new vector<int>(n);
createArray(temp, n);
//递归
permutation_v1_Helper(temp, n, result);
}
< 选择法 >
void permutation_v2_Helper(vector<int> *set, int const &n, vector<vector<int>> &result){
if (n==1) {
vector<int> *temp = new vector<int>(*set);
result.push_back(*temp);
return;
}
permutation_v2_Helper(set, n-1, result);//
for (int i(0); i <n-1; i++){
swap((*set)[i], (*set)[n-1]);//STL--交换
permutation_v2_Helper(set,n-1, result);
swap((*set)[i], (*set)[n - 1]);//STL--交换回来
//在递归过程中只要发生过交换,都对应有一个相同的交换,使其复原。
}
}
void permutation_v2(int const &n, vector<vector<int>> &result){
//生成数组
vector<int> *temp = new vector<int>(n);
createArray(temp, n);
//递归
permutation_v2_Helper(temp, n, result);
}
< 字典顺序: Fischer-Kruse 方法 >
//按字典排序---参见组合数学相关内容
//Fischer - Kruse 方法
void permutation_v3(int const &n, vector<vector<int>> &result){
//生成数组{1,2,3,..,n}
vector<int> *temp = new vector<int>(n);
createArray(temp, n);
result.push_back(*temp); //{1,2,3,..,n}
int swapPos1, swapPos2;
while (true){
//find swapPos1
for (swapPos1 = n - 1; swapPos1 > 0 && (*temp)[swapPos1] < (*temp)[swapPos1 - 1]; swapPos1--);
swapPos1--;
//结束条件
if (swapPos1 < 0)break;
//find swapPos2
for (swapPos2 = n - 1; swapPos2 > swapPos1 && (*temp)[swapPos1] > (*temp)[swapPos2]; swapPos2--);
//交换
swap((*temp)[swapPos1], (*temp)[swapPos2]);
//重排---得到字典序列中的下一个排列
//我这里直接使用sort,没有充分利用数组是逆序的这个性质,其实最好写一个排序逆序的函数,
//对于大数组来说,这能大幅度提高排序的速度。
sort(temp->begin()+swapPos1+1,temp->end());//temp->begin()+swapPos1+1==>(*temp)[swapPos1+1]
//记录到result中
result.push_back(*new vector<int>(*temp));
}
}
< main >
int main(){
vector<vector<int>> result;
int n;
cout << "请输入集合元素个数n:" << endl;
cin >> n;
permutation_v1(n, result);
cout << "permutation_v1的结果:-----------------------" << endl;
for (int i(0); i < result.size(); i++){
cout << "{";
copy(result[i].begin(), result[i].end(), ostream_iterator<int>(cout));
cout << "}";
cout << endl;
}
result.clear();
permutation_v2(n, result);
cout << "permutation_v2的结果:-----------------------" << endl;
for (int i(0); i < result.size(); i++){
cout << "{";
copy(result[i].begin(), result[i].end(), ostream_iterator<int>(cout));
cout << "}";
cout << endl;
}
result.clear();
permutation_v3(n, result);
cout << "permutation_v3的结果:-----------------------" << endl;
for (int i(0); i < result.size(); i++){
cout << "{";
copy(result[i].begin(), result[i].end(), ostream_iterator<int>(cout));
cout << "}";
cout << endl;
}
result.clear();
system("pause");
return 0;
}