4、输出全排列(递归方法)

  本来这篇早就该写了,但一直没有时间,鸽到了现在,略微有点愧疚。

题目

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

  讲真这题目确实抽象,我们看个例子

在这里插入图片描述
  让我想起了初中的数学题。。。

分析

  在我看来,递归确实难以理解,但这种题,每一位都循环着走是一种解法,但循环次数是随着输入的值动态变化的。以我目前的知识量,好像只有递归能解决这类问题。

  那么以123为例,它是怎样变化为其他5中样式的呢?

123->132 数字3移动到第二个位置上,数字2向后挪一位

123->213 数字2移动到第一个位置上,数字1向后挪一位

123->231 数字2移动到第一个位置上,数字1向后挪一位成213;数字3移动到第二个位置上,数字1向后挪一位

  以此类推

  因此,我们需要一个函数LeftSwap,实现一个数字往前挪,这个数字后面的数依次往后挪一位。

  但是,我们的变化是基于123这个基础的,所以需要一个函数RightSwap来还原为最初的样子。其实就是挪动的数字回原位,其他数字往前挪一位。

  问题解决一半了,剩下的就是递归。递归的关键就是出口,循环条件的改变。

  在左边数的下标等于右边数的下标的时候,就要跳出这一次递归,然后输出递归的结果。

代码分析

我们将代码拆分来看。
主函数

  利用循环给每数组赋值,进行递归,令0为左边值的下标,n-1为右边的下标。

#include<stdio.h>
#define MAX 9
}
int main()
{
	int n, a[MAX];
	scanf("%d", &n);
	int i;
	for (i = 0; i < n; i++)
	{
		a[i] = i + 1;
	}
	Array(a, 0, n - 1);
	return 0;
}

递归

  递归函数需要三个变量,数组,左边的下标Left,右边的下标Right。当Left = Right时,说明处理到最后一个元素了,这时到达递归终点,输出这一次的结果,然后返回到数组上一次递归调用的样子,再次递归。下一次递归,我们让Left+1,继续进行。

void Array(int a[], int Left, int Right)
{
	int i;
	if (Left == Right)
	{
		for (i = 0; i <= Right; i++)
			printf("%d", a[i]);
		printf("\n");
	}
	else
	{
		for (i = Left; i <= Right; i++)
		{
			LeftSwap(a, Left, i);
			Array(a, Left + 1, Right);
			RightSwap(a, Left, i);
		}
	}
}

变换函数

  其实很好理解,用Tag把移动的那个数的值存放起来,之后依次挪动位置,最后把空出来的位置放上Tag,完成了挪动 。

void LeftSwap(int a[], int Left, int i)
{
	int Tag, j;
	Tag = a[i];
	for (j = i; j > Left; j--)
		a[j] = a[j - 1];
	a[Left] = Tag;
}
void RightSwap(int a[], int Left, int i)
{
	int Tag, j;
	Tag = a[Left];
	for (j = Left; j < i; j++)
		a[j] = a[j + 1];
	a[i] = Tag;
}

代码实现

  最后放上实现的代码

#include<stdio.h>
#define MAX 9
void LeftSwap(int a[], int Left, int i)
{
	int Tag, j;
	Tag = a[i];
	for (j = i; j > Left; j--)
		a[j] = a[j - 1];
	a[Left] = Tag;
}
void RightSwap(int a[], int Left, int i)
{
	int Tag, j;
	Tag = a[Left];
	for (j = Left; j < i; j++)
		a[j] = a[j + 1];
	a[i] = Tag;
}
void Array(int a[], int Left, int Right)
{
	int i;
	if (Left == Right)
	{
		for (i = 0; i <= Right; i++)
			printf("%d", a[i]);
		printf("\n");
	}
	else
	{
		for (i = Left; i <= Right; i++)
		{
			LeftSwap(a, Left, i);
			Array(a, Left + 1, Right);
			RightSwap(a, Left, i);
		}
	}
}
int main()
{
	int n, a[MAX];
	scanf("%d", &n);
	int i;
	for (i = 0; i < n; i++)
	{
		a[i] = i + 1;
	}
	Array(a, 0, n - 1);
	return 0;
}

在这里插入图片描述

  • 28
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值