暑假练习1-1 字典序算法,从1到n的全排列

从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;
}

边打炉石边记录代码,又是颓废的一天。

猜你喜欢

转载自blog.csdn.net/xianqiuyigedao/article/details/107092206
1-1