字符串全排序和組合

http://blog.csdn.net/hackbuteer1/article/details/7462447

字符串的全排序:

1、全排列就是從第一個數字起每個數分別與它後面的數字交換。
2、去重的全排列就是從第一個數字起每個數分別與它後面非重複出現的數字交換。
3、全排列的非遞歸就是由後向前找替換數和替換點,然後由後向前找第一個比替換數大的數與替換數交換,最後顛倒替換點後的所有數據。

示例:

123的全排列有123、132、213、231、312、321這六種。首先考慮213和321這二個數是如何得出的。顯然這二個都是123中的1與後面兩數交換得到的。然後可以將123的第二個數和每三個數交換得到132。同理可以根據213和321來得231和312。因此可以知道——全排列就是從第一個數字起每個數分別與它後面的數字交換

方法一:

void Permutation(char *pStr,char *pBegin)
{
	if(!pStr || !pBegin)
	{
		return;
	}
	if(*pBegin == '\0')
	{
		static int num = 1;    //用於計數
		printf("第%d個排列\t%s\n",num++,pStr);
	}
	else
	{
		for(char *pCh=pBegin; *pCh != '\0';pCh++)
		{
			swap(*pBegin,*pCh);                 //第一個數與後面的數交換
			Permutation(pStr,pBegin+1);
			swap(*pBegin,*pCh);					//第一個數不能更改,它再一次和後面的數交換
		}
	}
}

方法二:

//k表示當前選取到第幾個數,m表示共有多少個數
void Permutation2(char *pStr,int k, int m) 
{
	if(!pStr)
		return;
	if(k == m)
	{
		static int num = 1;
		printf("第%d個排序\t %s \n",num++,pStr);
	}
	else 
	{
		for(int i=k;i<=m;i++)
		{
			swap(*(pStr+k),*(pStr+i));
			Permutation2(pStr,k+1,m);
			swap(*(pStr+k),*(pStr+i));
		}
	}
}

去重全排序:

由於全排列就是從第一個數字起每個數分別與它後面的數字交換。我們先嚐試加個這樣的判斷——如果一個數與後面的數字相同那麼這二個數就不交換了。如122,第一個數與後面交換得212、221。然後122中第二數就不用與第三個數交換了,但對212,它第二個數與第三個數是不相同的,交換之後得到221。與由122中第一個數與第三個數交換所得的221重複了。所以這個方法不行。

對122,第一個數1與第二個數2交換得到212,然後考慮第一個數1與第三個數2交換,此時由於第三個數等於第二個數,所以第一個數不再與第三個數交換。再考慮212,它的第二個數與第三個數交換可以得到解決221。此時全排列生成完畢。
這樣我們也得到了在全排列中去掉重複的規則——去重的全排列就是從第一個數字起每個數分別與它後面非重複出現的數字交換

//去重字符串全排序
bool isSwap(char * pBegin, char *pEnd)
{
	char *p;
	for(p = pBegin; p<pEnd;p++) 
	{
		if(*p == *pEnd) 
		{
			return false;
		}
	}
	return true;
}

void Permutation3(char *pStr, char *pBegin)
{
	if(!pStr || !pBegin)
	{
		return;
	}
	if(*pBegin == '\0')
	{
		static int num = 1;
		printf("第%d個排列\t%s\n",num++,pStr);
		//printf("%s\n",pStr);
	}
	else
	{
		for(char *pCh=pBegin; *pCh != '\0';pCh++)
		{
			if(isSwap(pBegin,pCh))
			{
				swap(*pBegin,*pCh);                 //第一個數與後面的數交換
				Permutation3(pStr,pBegin+1);
				swap(*pBegin,*pCh);					//第一個數不能更改,它再一次和後面的數交換
			}
		}
	}
}

字符串組合:

假設我們想在長度爲n的字符串中求m個字符的組合。我們先從頭掃描字符串的第一個字符。針對第一個字符,我們有兩種選擇:第一是把這個字符放到組合中去,接下來我們需要在剩下的n-1個字符中選取m-1個字符;第二是不把這個字符放到組合中去,接下來我們需要在剩下的n-1個字符中選擇m個字符。

void Combination(char *str)
{
	if(str == NULL)
	{
		return;
	}
	int length = strlen(str);
	vector<char> result;
	for(int i=1;i<=length;i++)
	{
		Combination(str,i,result);
	}
}

void Combination(char *str, int number, vector<char> &result)
{
	if(number == 0)
	{
		vector <char>::iterator iter = result.begin();
		for(; iter<result.end(); iter++)
		{
			printf("%c",*iter);
		}
		printf("\n");
		return;
	}
	if(*str == '\0')
		return;
	result.push_back(*str);
	Combination(str+1,number-1,result);
	result.pop_back();
	Combination(str+1,number,result);
}


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