///
//
// 2007-07-11
// By Rappizit@yahoo.com.cn
//
// 比较某排列生成算法的递归版和非递归版的效率
// 该算法生成 List [p..q] 的所有排列方式,看看函数 PermutationRecursion 的代码可以了解该算法
// 也可以参考以下截图【来源:《数据结构算法与应用-C++语言描述》(Sartej Sahni著,汪诗林译)例 1-3】
//
///
#include <iostream>
#include <time.h>
using namespace std;
template <class T>
inline void Swap (T List [], int a, int b)
{
if (a != b)
{
// 交换 a 和 b
// 如果要求生成的排列数数列是非递减的,并假设 a 是当前安排位置,
// 则这里应将 List [a..b] 循环右移
T temp = List [a];
List [a] = List [b];
List [b] = temp;
}
}
template <class T>
void PermutationRecursion (T List [], int p0, int p, int q)
{
// 生成 List [p..q] 的所有排列方式
// p0 是 p 的初始值,输出排列方式时要从 List [p0] 开始
int i;
if (p == q)
{
// 输出一个排列方式
//for (i = p0; i <= q; i ++)
// {
// cout << List [i]; // 比较测试时可以不输出
// }
//cout << endl;
}
else {
// List [p..q] 有多个排列方式,递归地产生这些排列方式
for (i = p; i <= q; i ++)
{
Swap (List, p, i);
PermutationRecursion (List, p0, p + 1, q);
Swap (List, p, i);
}
}
}
template <class T>
void PermutationRecursive (T List [], int p, int q)
{
PermutationRecursion <T> (List, p, p, q);
// 全部排列方式生成之后 List [p..q] 的元素顺序和最初的一样
}
template <class T>
void Permutation (T List [], int p, int q)
{
int i, p0 = p, cnt = 0, full = q - p + 1; // cnt 为已排好的数目, full 为排好所需的数目
int *Stack = new int [full];
i = p; // p 为当前安排位置
Stack [cnt ++] = i; // List [i] 为当前安排位置的可安排值
while (1) {
if (i == q) // 最后的位置没有可安排值
{
// 输出一个排列方式
//for (i = p0; i <= q; i ++)
// {
// cout << List [i]; // 比较测试时可以不输出
// }
//cout << endl;
// 回退到上一个可安排位置
do {
i = Stack [-- cnt];
Swap (List, p, i); // 恢复原顺序
p --;
} while (cnt && i >= q);
if (!cnt && i >= q ) // 最先的位置没有可安排值
{
break;
}
Stack [cnt ++] = ++ i; // 可安排位置的下一个可安排值为 List [++ i]
p ++; // 在 do 循环里面 p 被多减了一次,补回来
}
Swap (List, p, i); // 在 可安排位置 安排 可安排值
i = ++ p;
Stack [cnt ++] = i;
}
delete Stack;
// 全部排列方式生成之后 List [p..q] 的元素顺序和最初的一样
}
void main ()
{
clock_t start, finish;
double duration1, duration2;
char List [10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
int n = 10; // n 为要排列的数的数目
start = clock ();
Permutation <char> (List, 0, n-1); // 非递归
finish = clock ();
duration1 = (double)(finish-start)/(double)(CLOCKS_PER_SEC);
start = clock ();
PermutationRecursive <char> (List, 0, n-1); //递归
finish = clock ();
duration2 = (double)(finish-start)/(double)(CLOCKS_PER_SEC);
cout << duration1 << endl << duration2 << endl;
return;
}
#include <time.h>
using namespace std;
template <class T>
inline void Swap (T List [], int a, int b)
{
if (a != b)
{
// 交换 a 和 b
// 如果要求生成的排列数数列是非递减的,并假设 a 是当前安排位置,
// 则这里应将 List [a..b] 循环右移
T temp = List [a];
List [a] = List [b];
List [b] = temp;
}
}
template <class T>
void PermutationRecursion (T List [], int p0, int p, int q)
{
// 生成 List [p..q] 的所有排列方式
// p0 是 p 的初始值,输出排列方式时要从 List [p0] 开始
int i;
if (p == q)
{
// 输出一个排列方式
//for (i = p0; i <= q; i ++)
// {
// cout << List [i]; // 比较测试时可以不输出
// }
//cout << endl;
}
else {
// List [p..q] 有多个排列方式,递归地产生这些排列方式
for (i = p; i <= q; i ++)
{
Swap (List, p, i);
PermutationRecursion (List, p0, p + 1, q);
Swap (List, p, i);
}
}
}
template <class T>
void PermutationRecursive (T List [], int p, int q)
{
PermutationRecursion <T> (List, p, p, q);
// 全部排列方式生成之后 List [p..q] 的元素顺序和最初的一样
}
template <class T>
void Permutation (T List [], int p, int q)
{
int i, p0 = p, cnt = 0, full = q - p + 1; // cnt 为已排好的数目, full 为排好所需的数目
int *Stack = new int [full];
i = p; // p 为当前安排位置
Stack [cnt ++] = i; // List [i] 为当前安排位置的可安排值
while (1) {
if (i == q) // 最后的位置没有可安排值
{
// 输出一个排列方式
//for (i = p0; i <= q; i ++)
// {
// cout << List [i]; // 比较测试时可以不输出
// }
//cout << endl;
// 回退到上一个可安排位置
do {
i = Stack [-- cnt];
Swap (List, p, i); // 恢复原顺序
p --;
} while (cnt && i >= q);
if (!cnt && i >= q ) // 最先的位置没有可安排值
{
break;
}
Stack [cnt ++] = ++ i; // 可安排位置的下一个可安排值为 List [++ i]
p ++; // 在 do 循环里面 p 被多减了一次,补回来
}
Swap (List, p, i); // 在 可安排位置 安排 可安排值
i = ++ p;
Stack [cnt ++] = i;
}
delete Stack;
// 全部排列方式生成之后 List [p..q] 的元素顺序和最初的一样
}
void main ()
{
clock_t start, finish;
double duration1, duration2;
char List [10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
int n = 10; // n 为要排列的数的数目
start = clock ();
Permutation <char> (List, 0, n-1); // 非递归
finish = clock ();
duration1 = (double)(finish-start)/(double)(CLOCKS_PER_SEC);
start = clock ();
PermutationRecursive <char> (List, 0, n-1); //递归
finish = clock ();
duration2 = (double)(finish-start)/(double)(CLOCKS_PER_SEC);
cout << duration1 << endl << duration2 << endl;
return;
}
///
//
// 测试结果:
// 输出排列方式时递归版比较快,因为递归版的算法复杂度是 O(n!) , 非递归版的大于 O(n!) 而小于 O(nn!) 。
// 不输出排列方式时非递归版有时比递归版快(排列的数少于 10 时),不知为什么呢?
//
// 小结:
// 貌似白费心机来写这个排列生成算法的非递归版本了,T_T,除非某计算机不支持递归,会吗?
// 不过还是锻炼了思维,呵呵。。
// PS:该递归算法不是尾递归的,但是还是可以巧妙地利用堆栈实现非递归版本^_^
//
///