今天找到了一篇非常好的介紹康託展開的文章!!!
http://www.cnblogs.com/1-2-3/archive/2011/04/25/generate-permutation-part2.html
其核心是這一張圖:
根據這篇文章,寫出生成按序排列的全排列非常的簡單:
#include <iostream>
#include <vector>
#include <string>
#define N 4
using namespace std;
vector<char> letter; //存儲所需字母表
void initLetter() //初始化字母表
{
for(int i = 0; i < N; ++i){
letter.push_back('A' + i);
}
}
int fact(int n) //階乘
{
int result = 1;
for(int i = 1; i <= n; ++i){
result *= i;
}
return result;
}
void output(vector<char>& v) //輸出生成的結果
{
for(vector<char>::iterator it = v.begin(); it != v.end(); ++it){
cout << *it;
}
cout << endl;
}
void division(int n) //核心算法:輾轉相除生成排列
{
initLetter(); //每次先初始化字母表
vector<char> result;
int value, div;
for(int i = N - 1; i >= 0; --i){ //從(N-1)!除起
div = fact(i);
value = n / div; //商爲當前字母表下標
n = n % div; //餘數繼續用於輾轉相除
result.push_back(letter[value]); //商對應的字母加入到結果
letter.erase(letter.begin() + value); //從原始字母表中刪除(參數必須是iterator)
}
output(result);
}
int main()
{
int num = fact(N);
for(int i = 0; i < num; i++){ //從0~(N! - 1),每一個數對應一個排列
division(i);
}
return 0;
}
和原來的通過遞歸+回溯(http://blog.csdn.net/puppylpg/article/details/45287249)來生成全排列相比思路上簡單了不少!
#include <iostream>
#include <vector>
#define N 4
using namespace std;
vector<char> letter; //存儲所需字母表
vector<bool> visited; //標記
vector<char> result;
void initLetter() //初始化字母表
{
for(int i = 0; i < N; ++i){
letter.push_back('A' + i);
visited.push_back(false);
result.push_back(' '); //順便給result開闢空間
}
}
void output(vector<char>& v) //輸出生成的結果
{
for(vector<char>::iterator it = v.begin(); it != v.end(); ++it){
cout << *it;
}
cout << endl;
}
void f(int n) //核心算法:回溯。n是第n位
{
if(n == N){ //如果已經放置了N位,說明生成了一個排列
output(result);
return;
}
for(int i = 0; i < N; i++){ //對於每一位
if(visited[i] == false){ //如果沒有被用過,則可以用
visited[i] = true;
result[n] = letter[i];
f(n + 1); //遞歸繼續生成下一位
visited[i] = false; //回溯
}
}
}
int main()
{
initLetter();
f(0);
return 0;
}