今天找到了一篇非常好的介绍康托展开的文章!!!
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;
}