含重复字符的字符串全排列算法(思路+分析)

从昨天到现在一直在回顾字符串的全排列算法,之前简单地复习了不含重复字符的字符串全排列,所以这次想彻底解决该算法。关于不含重复字符的字符串全排列比较简单,直接用递归思路解决即可,简单代码如下:

template <class T>
void permute(T list[],int k, int m)
{
 int i;
 if (k==m)
 {
  for (i=0;i<=m;i++)
   cout<<list[i];
  cout<<endl;
 }

 for (i=k;i<=m;i++)
  {
   //if (list[k]!=list[i]&&i!=k)    //方法1:如果不同位置上的字符不相同,则进行交换
   //{
   // if ( IsSwap(list+i,list+m))//方法2:如果从该字符起,在区间[pBegin , pEnd)上没有重复字符,则进行交换,参考http://blog.csdn.net/hackbuteer1/article/details/7462447
   // {
    lswap(list+k,list+i);
    permute(list,k+1,m);
    lswap(list+i,list+k);
   //}
  }
   //}
}
template <class T>
inline bool IsSwap(T* pBegin , T* pEnd)  
{  
		T *p;  
		for(p = pBegin ; p < pEnd ; p++)  
			  {  
			      if(*p == *pEnd)  
				          return false;  
			   }  
		return true;  
} 

但是上述方法在存在重复字符的情况下则失效。上述代码中方法1和方法2为简单地改进,希望可以解决含重复字符的字符串全排列。但是在上机运行后发现是行不通的。简单分析了下原因,则是因为这两种改进均不能完成整个解空间的搜索,所以会漏掉部分解,也可能有重复解!

所以现在要换一种思路,在查找一定资源的基础上,发现了如下的有效算法,可以很好地实现字符串的全排列,包括重复字符存在的情况。该算法的思想是:

首先对原字符串进行排序,然后顺序地从原字符中逐个地取字符复制到解空间中,如果某字符和其前一个字符相同,则只处理一次。

简单地将就是在解空间的位置上逐个放置不同的字符,直至全部字符复制完毕。

举例来讲,对于abb,在第一个位置上有a,b两种情况,a时,只有b,b顺序。b时,则有a,b;b,a两种顺序。算法结束。代码如下:

#define MAXBUFFERSIZE 100
using namespace std;

void Permutation(char d[],char s[], int i, int l);
void Sort(char s[]);
int  count = 0;

void main()
{
	char s[MAXBUFFERSIZE];
	char d[MAXBUFFERSIZE];
	// input source string//
	cout<<"Input source string:"<<endl;
	gets(s);
	// 排序,排列并输出//
    Sort(s); 
	Permutation( d, s, 0, strlen(s));
	return;
}

// 运用递归输出各种排列//
void Permutation(char d[],char s[], int i, int n)
{
	int j;
	char temp;
	for(j = 0; j < n; j ++)
	{
		if ( j>0 && s[j] == s[j - 1] ) //如果当前字符和前一个字符串相同,则跳过该字符//
			;
		else if ( s[j] != '#' )    //如果标志为不为'#',即当前字符没有被复制//
		{
			d[i] = s[j];				//把源串的一个字符赋给目的串//
			temp = s[j];
			s[j] = '#';

			if(i == n - 1)
				{
					d[n] = '\0';
					cout<<setw(2)<<++::count<<":";         // 打印出其结果//
					cout<<d<<endl;
				}
			else 
				Permutation( d, s, i + 1, n);			// 递归调用//

			s[j] = temp;										// 回溯//
		}
	}
}

// 冒泡排序//
void Sort(char s[])
{
	int n = strlen(s);
	int i, j;
	char temp;
	for(i = 0; i < n - 1; i ++)
		for(j = i + 1; j < n; j ++)
			if(s[i] > s[j])
			{
				temp = s[i];
				s[i] = s[j];
				s[j] = temp;
			}
}

运行结果如下图所示:


当然,这种算法也存在着两个主要缺点:

1、额外增加了排序算法,耗时增加;

2、复制相当于使用了外部空间,空间使用增加。

发布了37 篇原创文章 · 获赞 85 · 访问量 52万+

猜你喜欢

转载自blog.csdn.net/xuanyuansen/article/details/7856815
今日推荐