字符串全排序和组合

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);
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值