递归策略 全排列问题

问题介绍:

全排列:从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。

例如:

1 、2 、3三个元素的全排列为:

{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}。

题目要求:

设计一个递归算法生成n个元素{r1,r2,…,rn}的全排列。

算法思路:

设R={r1,r2,…,rn}是要进行排列的n个元素,Ri=R-{ri}。 集合X中元素的全排列记为perm(X)。 (ri)perm(X)表示在全排列perm(X)的每一个排列前加上前缀得到的排列。R的全排列可归纳定义如下:

当n=1时,perm(R)=(r),其中r是集合R中唯一的元素;

当n>1时,perm(R)由(r1)perm(r1),(r2)perm(r2),…,(rn)perm(rn)构成。

核心代码:

Void Perm(Type list[ ] //存放n个元素数组, int k //头指针, int m //尾指针)  { (1) 

       if(k==m)    (2) //头指针和尾指针重合,意味着仅剩下一个元素

{      for(int i=0;i<=m;i++) (3) 

{       cout<<list[i];   (4)  //输出当前的排序序列

}

  }

else{  (5) 

for(int i=k;i<=m;i++) (6) 

{    

 swap(list[k],list[i]);   //交换序列中的两个数字  (7) 

perm(list,k+1,m);  //递归进入下一层循环(难点)(8) 

swap(list[k],list[i]);  //交换序列中的两个数字(9) 

        }

   }

}

个人理解:我借用《盗梦空间》提到多重梦境的概念来理解此题中的递归思想。

假设一开始数组 list={1,2,3},当我想求解list数组中元素的全排列,此时的头指针为下标0,尾指针为下标2。

在第一层中k=0,m=2  首先(2)语句,因为此时k!=m,因此执行(6)语句,(7)语句的作用是让list[0]与list[0]交换,list中顺序仍为123。然后执行(8)语句,进入第二层。

在第二层中k=1,m=2  首先判定(2)语句,因为此时k!=m,因此执行(6)语句,(7)语句是让list[1]与list[1]交换,list中顺序仍为123。然后执行第二层中的(8)语句,进入第三层。

在第三层中k=2,m=2  此时 k=m,因此执行(4)语句,输出序列123,同时由于完成了第三层的操作,返回第二层的(8)语句。

在第二层中执行(9)语句,作用是让list[1]自己交换,list中顺序仍为123。回到第二层(6)语句i++,此时i=2。执行(7)语句,list[1]与list[2]交换,list中顺序变为132。执行(8)语句,进入第三层,此时k=m,因此执行(4)语句,输出序列132,同时由于完成了第三层的操作,返回第二层的(8)语句。

执行第二层的(9)语句 list[1]与list[2]交换,顺序变为123,此时完成了第二层的操作,返回第一层的(8)语句。

执行第一层的(9)语句 list[2]与list[2]交换,顺序不变。回到第一层(6)语句i++,此时i=1,执行(7)语句,list[0]与list[1]交换,list中顺序变为213。执行(8)语句,后续操作跟前面操作类似,经过两次递归操作,最终输出213。完成第三层输出操作后,又执行第二层(9)语句,list[1]与list[1]交换,顺序不变,回到第二层(6)语句i++,此时i=2,执行(7)语句,list[1]与list[2]交换,list中顺序变为231。执行(8)语句,进入第三层循环,因为k=m,最终输出213。

完成第三层操作后,返回第二层(9)语句,list[1]与list[2]交换,list中顺序变为213。

完成第二层操作后,返回第一层(6)语句i++,此时i=2,执行(7)语句,list[0]与list[2]交换,list中顺序变为312,后续操作同理,最终分别输出312与321。

总结

我理解的递归问题,就是从一个难以解决的大问题,通过一层一层的嵌套,最终进入一个容易解决的小问题,再从小问题一层一层地推出最终大问题的结果。

递归算法的核心:1、边界条件(小问题的解决方式) 2、递归方程(如何从大问题一层一层进入小问题,从小问题一层一层推出大问题)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值