全排列(非遞歸版)

考慮全排列的非遞歸實現,先來考慮如何計算字符串的下一個排列。如"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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章