本来这篇早就该写了,但一直没有时间,鸽到了现在,略微有点愧疚。
题目
输出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;
}