PTA数据结构 习题2.8 输出全排列 (20分)

习题2.8 输出全排列 (20分)

请编写程序输出前n个正整数的全排列(n<10),并通过9个测试用例(即n从1到9)观察n逐步增大时程序的运行时间。

输入格式:

输入给出正整数n(<10)。

输出格式:

输出1到n的全排列。每种排列占一行,数字间无空格。排列的输出顺序为字典序,即序列a​1,a​2,⋯,an排在序列b​1,b2,⋯,bn之前,如果存在k使得a1=b1,⋯,ak=bk并且 ak+1 < bk+1

输入样例:

3

输出样例:

123
132
213
231
312
321

全排列字典序算法

全排列生成算法
所谓字典序,就是将元素按照字典的顺序(a-z,1-9)进行排列。strcmp就是以字典序来比较字符串。

字典序算法步骤

设P是集合
{ 1 , 2 , . . . . . . n − 1 , n } \{1,2,......n-1,n\} {1,2,......n1,n}
的一个全排列:P0P1…Pj-1PjPj+1…Pn

集合必须按照递增顺序排列好

  1. 从下标n开始递减,找出第一个比右边数字小的数字序号i
    P i < P i + 1 P_i<P_{i+1} Pi<Pi+1
  2. 在Pi右边的数字里,找到所有比Pj大的数字中最小的数字Pk,即
    k = min ⁡ { i ∣ P i > P j , i > j } k=\min\{i|P_i>P_j,i>j\} k=min{iPi>Pj,i>j}
  3. 交换Pi,Pj
  4. i右边的序列Pi+1Pi+2…Pn逆置,变为PnPn-1…Pi+1

C++代码如下

#include <iostream>
#include <cstdio>

int
fact( int n );

void
dictSeq( int a[], int n );

void
reverse( int a[], int n, int j );

void
swaq( int &a, int &b );

void
print_array( int a[], int n );

int
main( void )
{
	int *a;
	int n;
	scanf("%d", &n);
	a = new int[n];
	for( int i = 0; i < n; i++ ){
		a[i] = i+1;
	}

	int total = fact(n);	//全排列个数等于n!
	print_array( a, n );	//初始序列算一种排列, 在交换之前单独输出

	for( int i = 1; i < total; i++ ){	//让dictSeq执行total-1次, 输出除初始序列之后的所有可能
		dictSeq( a, n );
	}

	return 0;
}

void
dictSeq( int a[], int n )
{
	int i;
	for( i = n-1; i > 0; i-- ){
		if( a[i-1] < a[i] ){
			i--;
			break;	
		}
	}
	
	int min_j = i + 1;
    int min = a[min_j];
	for( int j = min_j; j < n; j++ ){
		if( a[j] > a[i] && min > a[j] ){
			min = a[j];
			min_j = j;
		}
	}
	swaq( a[min_j], a[i] );
	reverse( a, n, i );
	print_array( a, n );
}

void
reverse( int a[], int n, int i )
{
	int left = i + 1, right = n - 1;
	while( left < right ){
		swaq( a[left++], a[right--]);
	}
}

int
fact( int n )
{
	int fact = 1;
	do{
		fact *= n--;
	}while( n > 0 );
	
	return fact;
}

void
swaq( int &a, int &b )
{
	int temp;
	temp = a;
	a = b;
	b = temp;
}

void
print_array( int a[], int n )
{
	for( int i = 0; i < n; i++ ){
		printf("%d", a[i]);
	}
	printf("\n");
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值