如何写出递归程序
1.步骤
1.分析简单情况
2.画出栈的调用情况
3.分析每个栈单元的调用情况,找到每个栈单元的输出和输入
4.写出程序
2.示例
1.1 阶乘
- 分析简单情况
5! = 5 x 4 x 3 x 2 x 1
最简单的情况就是 1! = 1
2.画出栈的调用情况
- 黑色的数字表示函数接受的参数
- 红色箭头表示调用关系
- 蓝色箭头表示输入关系【并且在输入的时候还携带内容】,比如A红色箭头指向B,表示A栈单元的内容回复给B栈单元
- 橙色方框表示在每个栈单元的计算,橙色方框中内容的蓝色内容表示上一个栈单元传输过来的内容
3.分析每个栈单元的输入输出关系
比如在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.分析每个栈单元的输入输出关系
以内容中为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.分析栈的情况
- 红色箭头表示调用关系
- 蓝色箭头表示“输入”关系【并且在输入的时候没有携带内容】
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
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;//输出关系
}