递归算法的一些实例

来源:互联网 发布:单片机学习 编辑:程序博客网 时间:2024/06/08 10:11

递归算法的一些实例


递归算法实际上只需要找出递归表达式,或者说是n与n-1之间的关系即可,由于是直接调用自身,所以使用递归解决问题的函数通常都是很短的,因为只需要描述n与n-1之间的关系,以及终止递归的条件。

(1)阶乘
比如一个最简单的递归例子,求n的阶乘,递归的过程就是n*(n-1),终止的条件就是n=1,所以这个子函数就可以写成:

unsigned fac(unsigned n){    unsigned f;    if (n==0)        f = 1;    else        f = fac(n-1)*n;    return f;}

(2)排列组合
并非只有存在数学表达式的例子才能用递归的思想,只要能找出n和n-1的关系即可,比如说求n个人里面选k个人的组合数,已知如下关系:

由n选k个的组合数 = 由n-1选k个的组合数 + 由n-1选k-1的组合数

那么递归的表达式就可以写成:

f(n,k) = f(n-1,k) + f(n-1.k-1);

子函数可以写成:

int comm(int n,int k){    if(n < k)        return 0;    else if(n == k || k == 0)        return 1;    else        return comm(n-1,k) + comm(n-1,k-1);}

(3)汉诺塔
再比如经典的汉诺塔(Hanoi)问题

古代有一个梵塔,塔内有三个座A、B、C,A座上有64个盘子,盘子大小不等,大的在下,小的在上。有一个和尚想把这64个盘子从A座移到C座,但每次只能允许移动一个盘子,并且在移动过程中,3个座上的盘子始终保持大盘在下,小盘在上。在移动过程中可以利用B座,要求打印移动的步骤。如果只有一个盘子,则不需要利用B座,直接将盘子从A移动到C。

这样想这个问题:
如果有2个盘子,可以先将盘子1上的盘子2移动到B;将盘子1移动到c;将盘子2移动到c。这说明了:可以借助B将2个盘子从A移动到C,当然,也可以借助C将2个盘子从A移动到B。
如果有3个盘子,那么根据2个盘子的结论,可以借助c将盘子1上的两个盘子从A移动到B;将盘子1从A移动到C,A变成空座;借助A座,将B上的两个盘子移动到C。这说明:可以借助一个空座,将3个盘子从一个座移动到另一个。
如果有4个盘子,那么首先借助空座C,将盘子1上的三个盘子从A移动到B;将盘子1移动到C,A变成空座;借助空座A,将B座上的三个盘子移动到C。

从上面的过程来看,将n个盘子从A移动到C需要以下三个步骤:
1,将n-1个盘子移动到B;
2,将A上剩余的一个盘子移动到C;
3,将B上n-1个盘子移动到C。

上述步骤中,1和3都是将n-1个盘子从一个座移动到另一个座,这是递归过程,因为n-1个盘子的移动也需要上述三个步骤。。。以此类推,我们可写出实现汉诺塔问题的子函数:

void move(char A,char C){    cout<<A<<"-->"<<C<<endl;}void hanoi(int n,char A,char B,char C){    if (n==1)        move(A,C);    else        hanoi(n-1,A,C,B);        move(A,C);        hanoi(n-1,B,A,C);}

注意hanoi子函数中形参的顺序,因此第一个步骤是把n-1个盘子以C为中介从A移动B,而第三个步骤是把n-1个盘子以A为中介从B移到C。

(4)二叉树
二叉树是一种非常常见的数据结构,二叉树定义为每个结点最多有两个子树的树结构,左边的树称为“左子树”,右边的树称为“右子树”。

二叉树的建立是一个很明显的递归过程,因为一个结点生出两个树,这两个树的结点又分别对应生出两颗树……
二叉树的建立过程如下:

首先要建立一个二叉树的结点类:

class BitNode{    public:        ...//略    private;        char data;        BitNode *leftchild;        BitNode *rightchild;        }

public里面的成员函数先不用管,主要是完成一些初始化,左右树的设置和读取的工作。需要注意的是在私有成员里定了了用于存储数据的data,以及以及左右两个指针。

建立一个二叉树类:

class BiTree{    public:        ...        BiTree* create_tree();//创建二叉树        void pre_order(BitNode *r);//前序遍历        void in_order(BitNode *r);//中序遍历        void post_order(BitNode *r);//后序遍历    private:        BitNode *root;}

创建二叉树:

BitNode* BiTree::create_tree(){    BitNode* T;    char item;    cin>>item;    if (item != '#')    {        T = new BitNode;        T->data = item;        T->leftchild = create_tree();        T->rightchild = create_tree();        return T;    }    else    {        T = NULL;        return T;    }}

前中后序遍历分递归方法和非递归方法,此处只举递归的方法:

void BiTree::pre_order(BitNode *T){    if (T != NULL)    {        cout<<T->data;        pre_order(T->leftchild);        pre_order(T->rightchild);    }}void BiTree::in_order(BitNode *T){    if(T != NULL)    {        in_order(T->leftchild);        cout<<T->data;        in_order(T->rightchild);    }}void BiTree::post_order(BitNode *T){    if (T != NULL)    {        post_order(T->leftchild);        post_order(T->rightchild);        cout<<T->data;    }}
0 0