全排列算法,大致来讲有四种字典序法,递增进位制数法,递减进位制数法,邻位对换法,这里讲一下字典序方法。
首先看什么叫字典序,顾名思义就是按照字典的顺序(a-z, 1-9)。以字典序为基础,我们可以得出任意两个数字串的大小。
比如字符串“abcdg”和“abcfdg”,我们从左到右比较每一个字符的大小,发现第四个字符‘d’和‘f’,‘f’的字典序更大,因此前一个字符串比后一个字符串的字典序要小。
因此,对与“abc”,他的字典序最大的值是“cba”,最小的值是“abc”,其他的排序的字典序都在他们之间。因此,求一个串的全排列,我们只需要从串的字典序最小的排列开始,求出当前字典序的下一个字典序排序,直到字典序的值最大。我们就求出了所有的全排列!!!
对于,“abc”,我们从最小字典序“abc”开始,依次有:
abc(最小) acb bac bca cab cba(最大)
那么对于当前的序列我们如何求,他的下一个字典序呢.(所谓一个的下一个就是这一个与下一个之间没有其他的)?
一般算法可以分为三步:
对于串 5,8,7,9,3,6,4,2,1
1.我们从右向左找到第一个a[i],满足a【i】<a【i+1】,这里a【i】=3;
2.我们从a【i】开始向后,找最后一个a【j】>=a【i】,这里a【j】=4;
3.交换a【i】,和a【j】,有串 5,8,7,9,4,6,3,2,1
反转i位置后所有的元素5,8,7,9,4,1,2,3,6,得到下一个全排列
//arr是要排列的数组,n是数组的长度,当不存在下一个排列时返回false;
bool NextPermutation(int * arr,int n)
{
int i,j,k;
for(i=n-1;i>0;i--)//从尾巴开始找第一个arr【i】>arr【i-1】
if(arr[i]>arr[i-1])
break;
if(i==0) //如果没找到,则输入的已经是最大字典序
return false;
i--;
for(j=i+1;j<n;j++)//从i之后,开始找第一个不大于,a【i】的数,
if(arr[i]>=arr[j])//注意这里是不大于!!!
break;
j--;
swap(arr[i],arr[j]);
j=n-1;i=i+1;
while(i<j)
swap(arr[i++],arr[j--]);
return true;
}
字典序的不但能解决排列问题,也能解决组合问题,比如:从5个球中取三个,我们只要对0,0,0,1,1这样一个数组按照字典序进行全排列,就能遍历出所有组合。!!!!!当然,我们可以用stl里的next_permutation函数实现全排列!!!