递归下降分析程序的设计与实现_按照固定步骤写递归程序

6b548b0a8c3d3887407a4fa03bccc307.png

如何写出递归程序

1.步骤

1.分析简单情况

2.画出栈的调用情况

3.分析每个栈单元的调用情况,找到每个栈单元的输出和输入

4.写出程序

2.示例

1.1 阶乘

  1. 分析简单情况

​ 5! = 5 x 4 x 3 x 2 x 1

最简单的情况就是 1! = 1

2.画出栈的调用情况

c92f52fb902adbf73cee32ffe27c70f4.png
  • 黑色的数字表示函数接受的参数
  • 红色箭头表示调用关系
  • 蓝色箭头表示输入关系【并且在输入的时候还携带内容】,比如A红色箭头指向B,表示A栈单元的内容回复给B栈单元
  • 橙色方框表示在每个栈单元的计算,橙色方框中内容的蓝色内容表示上一个栈单元传输过来的内容

3.分析每个栈单元的输入输出关系

236c6baaf66e22551eace5b958686f22.png

比如在3的方框中

  • 调用关系(红色箭头):
    • 3会调用2
  • 输入关系(第一个蓝色箭头):
    • 3会接受2回复的内容
  • 输出关系(第二个蓝色箭头)
    • 3会往下一个栈单元发送内容

4.程序书写

模板如下

solve(){
    简单情况;

    调用关系;//必需
    输入关系;//非必需
    计算步骤;//必需
    输出关系;//非必需,输入关系与输入关系是一对,有输入必有输出,但是有些递归调用可能没有输入输出关系
}

所以阶乘的程序设计为:

int solve(int n){
    if(n == 1)//简单情况
        return 1;
    int temp = solve(n-1);//solve()是调用关系,temp是输入关系
    int result = temp * result;//计算内容
    return result;//输出关系
}
//然后可以化简
int solve(int n){
    if(n == 1)
        return 1;
    return n * solve(n-1);
}

1.2 斐波那契数列

1.分析简单情况

if(n == 1 || n == 2){
    return 1;
}//n指的是序号

2.画出栈的调用情况

  • 5表示输入的参数
  • 红色箭头表示调用关系
  • 蓝色箭头表示“输入”关系【输入并且在输入的时候还携带内容】,比如A红色箭头指向B,表示A栈单元的内容回复给B栈单元
  • 橙色方框表示在每个栈单元的计算,橙色方框中内容的蓝色内容表示其他栈单元传输过来的内容
  • 红色虚线表示栈的执行返回顺序

3.分析每个栈单元的输入输出关系

11bd0f69a2fc5627e31626476000007c.png

以内容中为3的那个栈单元为例:

  • 调用关系(红色箭头):
    • 3会调用2
  • 输入关系(第一个蓝色箭头):
    • 3会接受2和1回复的内容
  • 输出关系(第二个蓝色箭头)
    • 3会往下一个栈单元发送内容

4.程序设计

int solve(int n ){
    if(n == 1 || n == 2)
        return 1;
    //调用关系和输入关系
    int temp1 = solve(n-1);
    int temp2 = solve(n-2)
    //计算内容
    int result = temp1 + temp2;
    return result;//输出关系
}
//化简
int solve(int n){
    if(n==1 || n == 2)
        return 1;
    return solve(n-1)+solve(n-2);
}

1.3 将一个带头结点的单链表逆序打印

1.简单情况

当结点为null时

if(node == null)
    return;

2.分析栈的情况

e51099fb37f4c17ae9c4aee93718cf5a.png
  • 红色箭头表示调用关系
  • 蓝色箭头表示“输入”关系【并且在输入的时候没有携带内容】

3.分析单个栈单元的情况

自己分析

4.写程序

void reversePrint(LinkNode *node){//node是从第一个结点开始的,第一个结点不是头结点
    if(node == null)
        return;//简单情况
    reversePrint(node -> next);//调用关系
    print(node -> data);//计算内容,没有输入和输出关系
}

5.给大家的测试程序 c++ 直接复制带ide后运行

//  头文件LinkList.hpp
//  关于链表的基本操纵 创建  增 删 查
#ifndef LinkList_hpp
#define LinkList_hpp
#include "LinkList.hpp"
#include <stdlib.h>
#include <iostream>
typedef struct LinkNode{
    int data;
    struct LinkNode* next;
}LinkNode;
typedef LinkNode* LinkList;
//头插法初始化链表,导致输入的顺序与输出的顺序不同
bool init(LinkList &L){
    L = (LinkNode*)malloc(sizeof(int));//头结点
    L -> next = nullptr;//链表初始化
    LinkNode *newNode;
    int x;
    scanf("%d", &x);
    while (x != -1) {
        newNode = (LinkNode*)malloc(sizeof(int));
        newNode -> data = x;
        newNode -> next = L -> next;
        L -> next = newNode;//采用头插法
        scanf("%d", &x);
    }
    return true;
}
//尾插法,初始化链表
bool init_rear(LinkList &L){
    LinkNode *rear, *newNode;//尾指针
    rear = L = (LinkNode*)malloc(sizeof(LinkNode));//头结点指针
    L -> next = nullptr;
    int x;
    scanf("%d", &x);
    while(x != -1){
        newNode = (LinkNode*)malloc(sizeof(LinkNode));
        newNode -> data = x;
        rear -> next = newNode;
        rear = newNode;
        rear -> next = nullptr;
        scanf("%d", &x);
    }
    return true;
}
//按顺序打印所有的结点内容
void printAllnodes(LinkList L){
    LinkNode *p = L -> next;
    while (p) {
        printf("%d", p -> data);
        p = p -> next;
    }

}
void solve(LinkList &L){
    LinkNode *p = L -> next;//第一个结点
    LinkNode *p_rear = p -> next;

    LinkNode *head = L;
    head -> next = nullptr;//将头结点从旧链表中分离出来
    while(p){
        p -> next = head -> next;//采用头插法将遍历的结点插入,但是node与p都是指针,
                                    //两者的指针node -> next等同于 p -> next, 对还没有遍历的内容产生了影响,
                                    //所以设置一个新的指针,来保存p的后继指针来避免这种印象
        head -> next = p;
        p = p_rear;
        if(p_rear != nullptr)
            p_rear = p_rear -> next;
    }
}
#endif
//头文件 recursion.hpp 关于链表的递归操作
#ifndef recursion_hpp
#define recursion_hpp
#include "LinkList.hpp"
//将带有头结点的单链表逆序递归打印
void reversePrint(LinkList L){
    if (L == nullptr) {
        return;
    }
    reversePrint(L -> next);
    printf("%d", L->data);
}
#endif /* recursion_hpp */
//测试程序main.cpp
#include "recursion.hpp"
#include "LinkList.hpp"
int main(){
    LinkList L;
    init_rear(L);//初始化
    reversePrint(L->next);//传入链表中的第一个结点
}

结果:

输入 1 2 3 然后 -1表示输入结束,最后逆序的打印结果是-1

371e4a3d0f6b6d9d0efb0ad317c6499e.png

1.4 将一个带头结点的单链表采用递归的方式逆置

这个我不知道怎么用语言表达,有问题的话可以评论

reverseLinkList(LinkNode *node, LinkNode *p){
    if(node == null)
        return p;//简单情况
    p = reverseLinkList(node -> next, p);//调用关系,输入关系(返回的时候携带内容)
    p -> next = node;//计算内容的开始
    node -> next = null;
    p = node;//计算内容的结束
    return p;//输出关系
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值