您的位置:首页 > 其它

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

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

 

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

 

算法一:

基本思想:

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



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

伪代码:

 




算法分析:

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

 


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

 


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

 


最后我们得到:

 


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

 

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

C++代码:

[cpp] view
plain copy

 





#include <stdio.h>  

   

int n = 0;  

   

void swap(int *a, int *b)  

{  

    int m;  

    m = *a;  

    *a = *b;  

    *b = m;  

}  

void perm(int list[], int k, int m)  

{  

    int i;  

    if(k == m)  

    {  

        for(i = 0; i < m; i++)  

            printf("%d ", list[i]);  

        printf("\n");  

        n++;  

    }  

    else  

    {  

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

        {  

            swap(&list[k], &list[i]);  

            perm(list, k + 1, m);  

            swap(&list[k], &list[i]);  

        }  

    }  

}  

int main()  

{  

    int list[] = {1, 2, 3, 4, 5};  

    perm(list, 0, 5);  

    printf("total:%d\n", n);  

    return 0;  

}  

算法二:

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

伪代码:

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息