全排列递归算法

void swap(int a[],int i,int j)
{
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
void perm(int a[],int k,int m,int pk,int pm)
{
//k为中间变量,m初始化为参与排列元素的起始坐标和终止坐标
//pk,pm分别表示参与排列元素的起始坐标和终止坐标,整个递归过程保持不变
if(k==m)
{
for(int i=pk;i<=pm;i++)
{
printf("%d",a[i]);
}
printf("\n");
}else{
for(int i=k;i<=m;i++){
swap(a,k,i);
perm(a,k+1,m,pk,pm);
swap(a,k,i);
}
}
}
这个算法的大体思路我明白,就是(rj)perm(X)表示在全排列perm(X)的每一种排列前加上前缀rj所得到的排列。但是具体深入理解就不懂了,尤其是pern(a,k+1,m,pk,pm)这个核心的递归过程不懂,可不可以用1,2,3,4,5这个具体的例子给我讲解一下?已经想了很多天了,急求解答~

希望我的答复可以帮助你加深理解:

第一,perm函数中的条件for(int i=k;i<=m;i++)应更正为 for(int i=k;i<m;i++)

第二,你可以在核心步骤的前后打印有关变量的值,分析查看每一步的具体执行情况,这是编程调试的重要能力,要加强。
第三,以下是我提供的附件程序及运行结果(以1,2,3这个数组的全排列),可辅助分析:

1. 程序源码=================================================
#include <stdio.h>
#include <stdlib.h>
int N,P=0;

void swap(int a[],int i,int j)
{
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}

void perm(int a[],int k,int m,int pk,int pm)
{
int i;
/*k为中间变量,m初始化为参与排列元素的起始坐标和终止坐标
pk,pm分别表示参与排列元素的起始坐标和终止坐标,整个递归过程保持不变*/
if(k==m)
{
printf("----->perm %d :\n",P/N+1);/*打印提示*/
for(i=pk;i<pm;i++)
{
printf("%d ",a[i]);
P=P+1;
}
printf("\n\n");
}
else
{
for(i=k;i<m;i++)
{
printf("a %d,%d,%d,%d,%d\n",i,k,a[0],a[1],a[2]);
swap(a,k,i);
printf("b %d,%d,%d,%d,%d\n",i,k,a[0],a[1],a[2]);
perm(a,k+1,m,pk,pm);
printf("c %d,%d,%d,%d,%d\n",i,k,a[0],a[1],a[2]);
swap(a,k,i);
printf("d %d,%d,%d,%d,%d\n",i,k,a[0],a[1],a[2]);
}
}
}

int main()
{
/*调节以下N值及对应数组内容,可打印对应数组对应的全排列*/
N=3;
int t[]={1,2,3};
/*调节以上N值及对应数组内容,可打印对应数组对应的全排列*/

perm(t,0,N,0,N);
printf("----->Over!\n");/*打印提示*/
system("pause");
return 0;
}

2.打印结果 ============================================================

a 0,0,1,2,3
b 0,0,1,2,3
a 1,1,1,2,3
b 1,1,1,2,3
a 2,2,1,2,3
b 2,2,1,2,3
----->perm 1 :
1 2 3

c 2,2,1,2,3
d 2,2,1,2,3
c 1,1,1,2,3
d 1,1,1,2,3
a 2,1,1,2,3
b 2,1,1,3,2
a 2,2,1,3,2
b 2,2,1,3,2
----->perm 2 :
1 3 2

c 2,2,1,3,2
d 2,2,1,3,2
c 2,1,1,3,2
d 2,1,1,2,3
c 0,0,1,2,3
d 0,0,1,2,3
a 1,0,1,2,3
b 1,0,2,1,3
a 1,1,2,1,3
b 1,1,2,1,3
a 2,2,2,1,3
b 2,2,2,1,3
----->perm 3 :
2 1 3

c 2,2,2,1,3
d 2,2,2,1,3
c 1,1,2,1,3
d 1,1,2,1,3
a 2,1,2,1,3
b 2,1,2,3,1
a 2,2,2,3,1
b 2,2,2,3,1
----->perm 4 :
2 3 1

c 2,2,2,3,1
d 2,2,2,3,1
c 2,1,2,3,1
d 2,1,2,1,3
c 1,0,2,1,3
d 1,0,1,2,3
a 2,0,1,2,3
b 2,0,3,2,1
a 1,1,3,2,1
b 1,1,3,2,1
a 2,2,3,2,1
b 2,2,3,2,1
----->perm 5 :
3 2 1

c 2,2,3,2,1
d 2,2,3,2,1
c 1,1,3,2,1
d 1,1,3,2,1
a 2,1,3,2,1
b 2,1,3,1,2
a 2,2,3,1,2
b 2,2,3,1,2
----->perm 6 :
3 1 2

c 2,2,3,1,2
d 2,2,3,1,2
c 2,1,3,1,2
d 2,1,3,2,1
c 2,0,3,2,1
d 2,0,1,2,3
----->Over!
请按任意键继续. . .追问

m初始化为参与排列元素的起始坐标和终止坐标,那到底是起始坐标还是终止坐标?

追答

此算法里(指我附上的完整代码),m和pm以及pk都是常量,是约束数组下边界和上边界的常量,运行中值不变的,pk是下边界值,此算法里,恒为0,m和pm是上边界,恒为数组元素的个数——1、2、3这3个数求排列的情形,pk=0,m=pm=3,程序运行中它们的值一直如此。


并且m和pm是同一个参数,是重复的,分析如此,并且我已经测试过了。以下是我的分析截图,看后,应该会再次加深你对此算法的理解。多思考多分析,定有进步。祝进步!祝愉快!



追问

谢谢,谢谢~回答得很细哈~万分感谢,定当努力!

温馨提示:答案为网友推荐,仅供参考
相似回答