给定一个集合a,里面有n个元素,那么这n个元素不重复的排列方式有n!重。这个在数学上倒是众所周知的定理,推到起来也不太困难。但如果用程序来完成这个排列,一种简单的方式是如下这个
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int sum=0;
void perm(char *a, int k, int n)
{
if(k == (n-1))
{
int i;
for(i=0; i<n; i++)
{
printf("%c ", a[i]);
}
printf("\n");
sum++;
}
else
{
int i;
for(i=k; i<n; i++)
{
char t;
t = a[k];
a[k] = a[i];
a[i] = t;
perm(a, k+1, n);
t = a[k];
a[k] = a[i];
a[i] = t;
}
}
}
int main(int argc, char **argv)
{
char *a = argv[1];
int n = strlen(a);
perm(a, 0, n);
printf("n: %d\nsum: %d\n", n,sum);
return 0;
}
从键盘上收入字符串数组,会将所有的排列方式都打印出来,这个程序用到了递归。
递归背后的思想要归纳到数学上的无穷级数,但为了简化起见,省却了其中高数中的复杂的证明过程,这个留在下一阶段做,现在先来看下这个程序的逻辑。递归其实是一种不断递推的过程,a[n] 要由之前的a[n-1]之类的元素求得,一直推到可以直接算出结果的某个元素,观察下这个程序的21-34行,当将a[k]与a[i]交换后,再次执行perm函数,执行完毕后将a[k]与a[i]换回。
else
{
int i;
for(i=k; i<n; i++)
{
char t;
t = a[k];
a[k] = a[i];
a[i] = t;
perm(a, k+1, n);
t = a[k];
a[k] = a[i];
a[i] = t;
}
}
分析递归需要用到一点面向对象的知识,就是把该函数看作一个功能实体,当作一个完整的功能来看待,要实现什么功能,再次调用就可以了,一旦展开函数调用那就会对分析构成非常严重的灾难。consider such function in math:
f[n] = <1> a;(n<=2);
<2> f[n-1]+f[n-2]; (a>2);
if we use the measures of math analysist, thus the const of time and how much difficulty that function costs would be easily figured out.