全排列
全排列顾名思义,就是对一系列的单个字符进行排列,所有的排列结果就称为全排列,列如“1,2,3”,其全排列就有:“123”、“132”,“213“、”231“、312”,“321”,有6种,可以发现其全排列的个数就是n!。
现在我们知道了什么是全排列,接着我们就要明白全排列的原理,因为全排列的个数是n!,它的个数恐怖式增长,我们不可能全部列出来,我们要培养计算机思维,这个问题如何用计算机解决,既然使用计算机,那我们就要考虑全排列的产生过程,即找规律。
我们现在的全排列是按照字典序递增排列的,只有有一定的规则,我们才能方便找规律。
首先,举个例子1,2,3,4的全排列:1234,1243,1324,1342,·····4321
排列即交换某些字符的位置,那交换哪些字符能够保证使最后的排列保证递增排序呢,就像1234的下一个是1243,是3和4的位置进行交换,能不能是其他字符交换呢,那当然不能,因为1234的下一个1243就是字典序列最小的那一个,那下一个呢?1324,1后面的所有字符都发生了改变,1342,3后面的字符都发生了改变,那么,改变的位置k如何确定呢?
k之后的位置该如何改变呢?
我们上代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[100], n;
int permutation()
{
int flag = 0;//用来标记是否还有k,即是否是最后一个排列
int k;
for (int i = n - 2; i >= 0; i--)
{
if (a[i] < a[i + 1])//y用来找k的位置,从后往前找到一个可以交换的k的位置,小于就说明可以交换,有新的序列
{
flag = 1;
k = i;
break;
}
}
if(flag == 0)
return 0;
for (int i = n - 1; i > k; i--)
{
if (a[i] > a[k])//找到了k的位置,那么该和哪一个位置的值交换呢,从后往前找到第一个比它大的值
{
swap(a[i], a[k]);
break;
}
}
sort(a + k + 1, a + n);//把k后面的值从小到大排序,为什么排序呢?
//首先这样可以保证这种状态下字典序最小,还有为什么与k交换的是第一个比它大的值,为什么不是其他值,这个排序是非常重要的
return 1;
}
int main()
{
while (std::cin >> n)
{
int cnt = 1;
for (int i = 0; i < n; i++)
{
std::cin >> a[i];
}
while (permutation())
{
cnt++;
for (int i = 0; i < n; i++)
std::cout << a[i] << " ";
std::cout << std::endl;
}
std::cout << cnt <<std::endl;
}
return 0;
}
可能我的描述还是不能使你理解,那么希望你可以用1234来模拟一遍代码,来看一下执行过程,这个过程可以便于你的理解。
我们知道在C++里有很多封装好的库函数,没错,就是你想的那样,在C++有全排列的函数next_permutation(start,end),start是你要排列的首地址,end尾地址,作用就是求一个排列的下一个排列,可以遍历全排列。
这个函数需要头文件
#include
上代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[100], n;
int main()
{
while (std::cin >> n) {
for (int i = 1; i <= n; i++)
std::cin >> a[i];
do {
for (int i = 1; i <= n; i++)
std::cout << a[i] << " ";
std::cout << std::endl;
}while(next_permutation(a+1, a +1+ n));
}
return 0;
}
不要感觉有了函数就感觉知道原理没什么用了,你只有知道原理,才能更好的使用,才能更灵活的使用。
外话:
递归实现全排列:
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[100], n;
void permutation()
{
int flag = 0;
int k;
for (int i = n - 2; i >= 0; i--)
{
if (a[i] < a[i + 1]){
flag = 1;
k = i;
break;
}
}
if (flag == 0)
return ;
for (int i = n - 1; i > k; i--)
{
if (a[i] > a[k]){
swap(a[i], a[k]);
break;
}
}
sort(a + k + 1, a + n);
for (int i = 0; i < n; i++)
std::cout << a[i] << " ";
std::cout << std::endl;
permutation();
return ;
}
int main()
{
while (std::cin >> n) {
for (int i = 0; i <n; i++)
std::cin >> a[i];
permutation();
}
}
其实递归实现我想了很久,但是还是没有想到怎么实现,那你可能会好奇上面的代码是什么鬼,你再看上面的代码和第一个代码就发现,递归循环调用同一个函数,我就偷了个懒,只是把while循环给换了种形式,希望有大佬可以帮助。
学习的时候看的大佬文章:大佬传送门