(二)非递归的全排列算法
算法思路:
对于一个序列,用first表示起始位置,last表示结束位置,用区间可表示为[first,last],初始状态该序列的值递增:
1、从后往前比较相邻两数据(i=last-1,j = last,每次比较后i--且j--),若前者小于后者(*i < *j,*i表示i位置对应的值),标志前者值为X1(X1 = *i)(位置PX = i)表示将被替换;
2、再次从后往前搜索第一个不小于X1的数据,值记为X2;
3、交换X1,X2;
4、把[PX+1,last]标记范围逆置。
要点:为什么这样就可以保证得到的为最小递增。
从后往前比较相邻两数据,上述算法得到位置PX,那么[PX+1,last]总是递减的,[first,PX)没有改变,意味着已经得到[PX+1,last]的全排列。X2位置后的值比X1小,X2位置前的值比X1大,故交换X1,X2后,[PX+1,last]依然递减。因为X2>X1,所以不管X2后面怎样排列都比原数列大,反转[PX+1,last]使此子数列(递增)为最小。
从而保证的新数列为原数列的字典序排列next。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
//交换
void Swap(char *a, char *b)
{
char temp = *a;
*a = *b;
*b = temp;
}
void Reverse(char *a, char *b)
{
//地址比较
while(a < b)
Swap(a++, b--);
}
bool Permutation(char a[], int n)
{
char *pEnd = a + n -1;
char *p, *q, *pFind;
p = pEnd;
while(p != a)
{
q = p;
p--; //p为前一位,q为后一位
if(*p < *q) //前者小于后者
{
pFind = pEnd; //从有效位开始比较
while(*pFind <= *p) //找到第一个比p大的数字
--pFind;
Swap(pFind, p); //交换
Reverse(q,pEnd); //逆置
return true;
}
}
return false; //不存在下一个排列
}
int main()
{
char a[100];
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
a[i] = i+'1';
a[n] = '\0';
int i = 1;
do{
printf("第%3d个排列\t%s\n", i++, a);
}while (Permutation(a, n));
return 0;
}