从1到n的全排列。
题干:
输入一个整数n(n <= 9),输出1、2、3、······、n这n个数的全排列(按照字典序输出)。
Input
一个整数n
Output
多行,每行表示一种排列,行内使用空格分隔相邻两数。
Sample Input
3
Sample Output
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
**思路:**参考了https://blog.csdn.net/Horizenn/article/details/82380296
对于这种全排列,人写是简单,但是要机器实现就要有一定的技巧。
我习惯用从1到5来举例和思考写法。
首先明白何为字典序,简单来说就是从小到大,已从1到5为例,应是12345为首,54321为末。
对于其中的变化,自然应该从后往前变化。
1.从未记录过的末端依次找一手左边小于右边的两数,如12345中的45.
2.记录左边的数的位置为i(即45中的4),从末端开始找第一个大于他的数,两者交换位置。
如1 2 3 4 5,4 与 5 交换位置。
3.将位置为i后的数进行倒置,目的在于完成字典序。因为第二步是把大数与前头的小数互换,但是从字典序来讲,要将较小的数前置。
4. 判断是否为完全倒置,如54321,则退出循环。否则,返回步骤1.
#include <iostream>
#include <vector>
using namespace std;
void output(vector<int> v)//输出
{
for(int i=0; i<v.size(); ++i)
{
if(i!=0) //经典不读题,老彩笔了。
{
cout<<" ";
}
cout << v[i];
}
cout << endl;
}
void swap(vector<int>::iterator n, vector<int>::iterator m) //交换
{
int temp;
temp = *n;
*n = *m;
*m = temp;
}
void reverse(vector<int>::iterator n, vector<int>::iterator m)//逆置
{
while(n<m)
{
swap(n,m);
n++;
m--;
}
}
int main(void)
{
int n;
cin >> n;
vector<int> v;
for(int i=1; i<=n; i++)
v.push_back(i);
//1-n
vector<int>::iterator p,i;
output(v);//输出1234
do
{
for(p=v.end()-1; p!=v.begin(); --p)
{
if(*p>*(p-1)) //从未记录过的末端依次找一手左边小于右边的两数,如12345中的45.
{
i=p-1; //记录这个左边数的位置为i。
for(vector<int>::iterator p1=v.end()-1; p1!=i; --p1) //倒着找比i这个位置大的数,交换。比如12345,第一次循环i在第四个位置,第二次在第三个位置。要在前边的数12固定的情况下,后边三个数分别在第三个位置呆一呆。且交换之后,相对较小的数靠后,就有依次123、124、125的排列。
{
if(*p1>*i)
{
swap(p1,i);
reverse(++i,v.end()-1);//倒置,遵循字典序。有12453且有12435。
output(v);
break;
}
}
break;
}
}
if(p==v.begin()) //标记到头
break;
}while(true);
return 0;
}
边打炉石边记录代码,又是颓废的一天。