递归初探

C通过运行时堆栈支持递归函数的实现,有趣的是,标准并未说明递归需要堆栈。但是,堆栈非常适合于实现递归,所以很多编译器都使用堆栈来实现递归。——《C和指针》

以组合数C(n,m)举例:

C(n,m)=C(n-1,m)+C(n-1,m);
当n>=0时,C(n,0)=1, C(n,n)=1 。

递归算法代码:

int  comb(int n, int m)
{
    if(n<m || n<0 || m<0)
    return 0;
    if(n>=0)
    {
        if(m==0)
        return 1;
        if(n==m)
        return 1;
    }
    return comb(n-1,m)+comb(n-1,m-1);
}
复制代码

以C(4,3)来计算: C(4,3)=C(3,3)+C(3,2)=1+C(2,2)+C(2,1)=1+1+C(1,1)+C(1,0)=1+1+1+1=4

利用栈先进后出算法思想的非递归算法

#include  <stdio.h>
#include  <stdlib.h>
#include  <string.h>

#define  StackSize      100
//DataType为元素的数据类型,stack用于存储栈中的数据元素的数组,top为栈顶指针
typedef   int  DataType;
typedef  struct   
{
    DataType    stack[StackSize];
    int         top;    
}SeqStack;

//初始化栈
void   StackInit(SeqStack  *S)
{
    S->top=0;
}

//判断栈是否为空
int     StackEmpty(SeqStack S)
{
        if(S.top==0)
        return 1;
        else
        return 0;
}

//取栈顶元素
int     GetTop(SeqStack S, DataType  *e)
{
    if(S.top<=0)
    {
        printf("栈已经空!\n");
        return  0;
    }
    else
    {
        *e=S.stack[S.top-1];
        return 1;
    }
}

//将元素入栈
int     PushStack(SeqStack  *S, DataType  e)
{
    if(S->top==StackSize)
    {
        printf("栈已经满!\n");
        return 0;
    }
    else
    {
        S->stack[S->top]=e;
        S->top++;
        return 1;
    }
}

//将栈顶元素出栈
int    PopStack(SeqStack  *S,  DataType  *e)
{
        if(S->top==0)
        {
            printf("栈已经空!\n");
            return 0;
        }
        else
        {
            S->top--;
            *e=S->stack[S->top];
            return   1;
        }
}

//求栈的长度
int  StackLength(SeqStack  S)
{
    return S.top;
}

//清空栈
void    ClearStack(SeqStack  *S)
{
    S->top=0;
}

int  comb(int n, int m)
{
    if(n>=0)
    {
        if(m==0)
        return 1;
        if(n==m)
        return 1;
    }
    return comb(n-1,m)+comb(n-1,m-1);
}

//判断是否需要入栈
int  comb_cal(int n, int m)
{
    if(n>=0)
    {
        if(n==m)
        return 1;
        if(m==0)
        return 1;
    }
    return 0;
}

int  comb_stack(int n, int m)
{
    int i=n;
    int j=m;
    int sum=0;
    int temp1,temp2;
    //A Stack存放n值,B Stack存放m值,两个同时入栈出栈,
    //所以判断为空只需要判断一个即可
    SeqStack  A,B;  
    
    if(n<m || n<0 || m<0)
    return 0;
    
    StackInit(&A);
    StackInit(&B);
    PushStack(&A,i);
    PushStack(&B,j);

    while(!StackEmpty(A))
    {
        GetTop(A,&i);
        GetTop(B,&j);
        if(comb_cal(i,j)==0)
        {
            PopStack(&A,&temp1);
            PopStack(&B,&temp2);
            i--;
            PushStack(&A,i);
            PushStack(&B,j);
            j--;
            PushStack(&A,i);
            PushStack(&B,j);
        }
        else
        {
            PopStack(&A,&temp1);
            PopStack(&B,&temp2);
            sum+=1;
        }
    }
    return sum;
}


int  main()
{
    int b=comb_stack(4,3);
    int c=comb(4,3);
    printf("b:%d\n",b);
    printf("c:%d\n",c);
    return 0;
}
复制代码

上面的递归算法代码很好写,有直接的递归计算公式,但有些递归算法代码就不那么好写了,那么递归算法代码该怎么去写呢?今天在网上看到一种根据数学归纳法的思维来写递归算法代码。

最简单和常见的数学归纳法是证明当n等于任意一个自然数时某命题成立。证明分下面两步:

1.证明当n= 1时命题成立。

2.假设n=k时命题成立,那么可以推导出在n=k+1时命题也成立。(k代表任意自然数)

以链表反序算法为例:

第一步 n=1 ==>也就是链表为空或者链表只有一个元素的时候,这时候可以直接返回链表头指针 这是递归限制条件

第二步 假设n=k时成立,推导出n=k+1时也成立==>当程序能够反序head->next时(也就是图中空白框部分包括了k个结点全部完成了反序后)该如何处理呢? 需要2步:

1.head->next结点的next指针指向需要改变为指向head

2.head结点的next指针指向需要改为指向NULL

typedef struct Node{
    int data;
    Node *next;
} Node, *List;
Node * reverseList(List head)
{
    //如果链表为空或者链表中只有一个元素
    if(head == NULL || head->next == NULL)
    {
        return head;
    }
    else
    {
        //先反转后面的链表,走到链表的末端结点
        Node *newhead = reverseList(head->next);
        //再将当前节点设置为后面节点的后续节点
        head->next->next = head;
        head->next = NULL;
        
        return newhead;
    }
}
复制代码

一旦你理解了递归,阅读递归函数最容易的方法不是纠缠于它的执行过程,而是相信递归函数会顺利完成它的任务。如果你的每个步骤正确无误,你的限制条件设置正确,并且每次调用之后更接近限制条件,递归函数总是能够正确地完成任务。————《C和指针》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值