您的位置:首页 > 其它

含有重复字符的全排列问题以及按字典序打印

2017-09-24 17:55 204 查看
关于字符的全排列问题也是有很多算法的,今天我就来介绍递归的Perm算法。直接看题吧。。。

给定一字符串,可能含有相同元素。请借助递归设计算法求出该字符串的所有不同的排序。

输入格式:

给定一串字符串(长度小于等于9,且至少有3个字符相同)。

输出格式:

每行输出一个字符串。按照字典序递增的顺序输出,每个排列占一行。

最后一行输出不同排列的个数。

题目大体意思就是要我们求一个字符串的全排列,说到递归,那么Perm算法出来了,Perm算法核心思想是把m个待排元素每一个依次拿到首位,剩下的m-1个组成新的待排元素传入Perm进行相同的操作……….以此类推,直到元素递归到只有一个了,就依次打印出来 形成一个排列

先上算法的核心部分:

void Perm(char b[],int low,int high,int& n)//这里把待排序元素放入char型数组b中,待排元素起始下
//标为low,末尾下标为high,n用来计有多少种不同的排列组合
{

if(low == high)              //如果递归排到只有最后一个元素,就按序打印出来
{
for(int i = 0;i < low;i++)
{
printf("%c",b[i]);

}
n++;                  //打印一次计数值加1
printf("\n");             //每打印一次排列就换一次行
}
else                         //如果传进来的待排字符不止一个字符
{
for(int i = low;i < high;i++)
{

swap(b[low],b[i]);     //把每个元素挨个拿到首部low的位置
Perm(b,low+1,high,n);  //除拿到首部之外剩下的再进入Perm递归
swap(b[low],b[i]);     //还原字符串为交换前的样子,以进行下个字符的交换
}

}
}


这只是Perm最原始思想的体现,目前还不具备处理重复元素的能力,比如aabc,把第一个a拿到首位和把第二个a拿到首位,再让其与字符进行全排列后的效果是一样的,因此,我们在交换前应该加一个判断,如果在该字符位置之前存在相同的字符,该字符就不进行多余的交换了,跳往下一个字符的判断,修改代码如下:

for(int i = low;i < high;i++)
{
if(isSwap(b,low,i)) //交换前判断之前是否有相同的元素被拿到首位过
{
swap(b[low],b[i]);
Perm(b,low+1,high,n);
swap(b[low],b[i]);
}
}


当然了,到目前位置还存在的一个问题就是没有满足字典序打印的问题,由于该算法是一个元素一个元素输出的,所以没有办法在得到结果之后在进行排序,只得对算法本身加以调整,如下:

for(int i = low;i < high;i++)
{
sort(b+low,b+high);//把每次递归传进来的元素先排个序,用了sort库函数,它包含在在头文件<algorithm>中
if(isSwap(b,low,i))
{
swap(b[low],b[i]);
Perm(b,low+1,high,n);
swap(b[low],b[i]);
}
}


这样工作就都做完啦。。

这一题完整代码如下:

#include<iostream>

#include<algorithm>

using namespace std;

void swap(char& a,char& b)      //两个元素进行交换
{
char c = a;
a = b;
b = c;
}

bool isSwap(char b[], int start, int i) //i为该元素下标
{
for(int k = start; k<i;k++)   //判断在该元素之前有没有相同元素
if(b[k] == b[i])
return false;         //如果有,则返回false
return true;
}
void Perm(char b[],int low,int high,int& n)  //核心的算法啦
{

if(low == high)
{
for(int i = 0;i < low;i++)
{
printf("%c",b[i]);

}
n++;
printf("\n");
}
else
{
for(int i = low;i < high;i++)
{
sort(b+low,b+high);
if(isSwap(b,low,i))
{
swap(b[low],b[i]);
Perm(b,low+1,high,n);
swap(b[low],b[i]);
}
}

}
}

int main()
{
int  n = 0;      //计数用的
string str;
cin>>str;        //用字符串接收待排元素

char b[9] ;
int i = 0;
while(str[i]!='\0')
{
b[i] = str[i];       //把待排元素装进字符数组中
i++;
}
Perm(b,0,str.length(),n); //调用Perm进行排序
cout<<n<<endl;            //输出总排列个数

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐