003-生成排列-归纳法-《算法设计技巧与分析》M.H.A学习笔记

我们来生成1,2,3,...,n的全排列,这里只说两种与归纳法有关的算法,其他的算法还有几个,也有不是递归的算法,这里先不多讲。

 

首先吐槽一下这两个伪代码看书看了很久才理解,原因就是他们放在归纳法这一章里面,还配了一堆让人更加混乱的文字解释。其实递归就是递归,递归总是很好理解的,跟着代码运行一遍跑到停止的条件(dfs)或是每一层(深度)每一层(深度)去模拟(bfs),再把图画出来,过程总是很明朗的,递归真的只是算法里最容易理解的东西。

 

算法一:

基本思想:

假设已经生成了2,3,...,n的全排列,再在其前面加上1,类似的,生成1,3,...,n的全排列,再在前面加上2,以此类推。然后递归的,依次缩小已经生成的全排列的规模,指导只剩下一个数。下面的伪代码用交换的方法来为每个位置放置不同数字,其实这和从无到有构造一棵多叉树是没有区别的。搜索的路径都是下面这个样子。


看下书中的伪代码,理解了很久才看懂,其实只要知道其中的交换实质上只是为了给各个位置安排不同的数这一点,代码就明朗了。

伪代码:

 


算法分析:

对于复杂度,我们有下面这个递推式:

 

然后下面的知识来自高考数学倒数第二题第一小题的求数列表达式:

 

下面用到积分,我的噩梦。

 

最后我们得到:

 

这里贴图贴得有点啰嗦,但这个思路是很多递归算法计算复杂度的思路。以后类似的计算就不贴了,可以自己举一反三。

 

最后,贴一下找到的一个C++代码:

C++代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.    
  3. int n = 0;  
  4.    
  5. void swap(int *a, int *b)  
  6. {  
  7.     int m;  
  8.     m = *a;  
  9.     *a = *b;  
  10.     *b = m;  
  11. }  
  12. void perm(int list[], int k, int m)  
  13. {  
  14.     int i;  
  15.     if(k == m)  
  16.     {  
  17.         for(i = 0; i < m; i++)  
  18.             printf("%d ", list[i]);  
  19.         printf("\n");  
  20.         n++;  
  21.     }  
  22.     else  
  23.     {  
  24.         for(i = k; i < m; i++)  
  25.         {  
  26.             swap(&list[k], &list[i]);  
  27.             perm(list, k + 1, m);  
  28.             swap(&list[k], &list[i]);  
  29.         }  
  30.     }  
  31. }  
  32. int main()  
  33. {  
  34.     int list[] = {1, 2, 3, 4, 5};  
  35.     perm(list, 0, 5);  
  36.     printf("total:%d\n", n);  
  37.     return 0;  
  38. }  


算法二:

另一个Θ(nn!)的算法,其实和前面的算法并没有什么本质的区别。不同之处在于前面的算法是每次给一个位置安排一个数,而这里是每次给一个数安排一个位置。一点都不乱,嗯。

伪代码:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这波lucio来全学了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值