考虑全排列的非递归实现,先来考虑如何计算字符串的下一个排列。如"1234"的下一个排列就是"1243"。只要对字符串反复求出下一个排列,全排列的也就迎刃而解了。
如何计算字符串的下一个排列了?来考虑"926520"这个字符串,我们从后向前找第一双相邻的递增数字,"20"、"52"都是非递增的,"26 "即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到"956220",然后再将替换点后的字符串"6220"颠倒即得到"950226"。
#include<stdio.h>
#include<string.h>
int partition(char *str, int low, int high)
{
char key;
key = str[low];
while(low < high)
{
while(low < high && str[high] > key) high --;
str[low] = str[high];
while(low < high && str[low] < key) low ++;
str[high] = str[low];
}
str[low] = key;
return low;
}
void quicksort(char *str, int low, int high)
{
int p;
if(low < high)
{
p = partition(str, low, high);
quicksort(str, low, p - 1);
quicksort(str, p + 1, high);
}
}
int point,min_bigger;
int find(char *str, int point)
{//从后往前找的第一个比替换数大的数一定就是要找的最小数,
int ans;
int i;
int len = strlen(str);
for(i = len - 1; i > point; i --)
{
if(str[i] > str[point])
{ans = i;break;}
}
return ans;
}
void swap(char *str, int a, int b)
{
char c;
c = str[a];
str[a] = str[b];
str[b] = c;
}
void convert(char *str, int a)
{
int i;
for(i = 0; i < (strlen(str) - 1 - a)/2; i ++)
{
swap(str, a + 1 + i, strlen(str) - 1 - i);
}
}
void pailie(char *str)
{
puts(str);
int len = strlen(str);
int i, flag = 1;
while(flag)
{
for(i = len - 2; i >= 0; i --)
{
if(str[i] < str[i + 1])
{point = i;break;}
}//找到替换点
if(i == -1){flag = 0;break;}
min_bigger = find(str, point);//找到其后大于它的最小值
swap(str, point , min_bigger);
convert(str, point);
puts(str);
}
}
int main(void)
{
char str[10];
while(gets(str))
{
quicksort(str, 0, strlen(str) - 1);
pailie(str);
}
return 0;
}