递归和迭代

Recursion and Iteration

1、递归和迭代

递归(Recursion)和迭代(Iteration)是编程当中出现频率非常高的两个大概。对于迭代,理解起来自然是没有难度的,就是从头去遍历某个数据结构,到终点就退出。所以迭代非常适用于处理一些单向且线性的数据结构。下图是迭代的流程示意图。
在这里插入图片描述
但递归确实一个令许多人头疼的问题,因为在实现的迭代的过程中,经常需要函数自己调用自己,就跟套娃一样。而递归的过程其实分为两个部分,第一个部分是前向的去遍历数据结构,这点和迭代完全一样。而另一部分则是从终点方向迭代回起点。两个部分以调用函数本身的指令为分界线。下图是递归的示意图。
在这里插入图片描述
递归非常适用于处理一些反向任务,同时在处理一些套娃任务也有十分高效。为加深理解,下面举两个例子。
例子一:设当前有一个N结点的链表,每一个节点有一个height变量。现希望写一个程序,让最末端的节点height为0,倒数第二的节点height为1,依次类推,位于头部的节点height为N。注:N是一个未知数。
分析:由于我们不知道N是多少,所以如果使用迭代的方法,得先遍历一次链表,然后得到N。在遍历一遍链表,再依次给各个节点的height赋值。也就是说使用迭代的方法需要遍历两次链表。
而如果使用递归的方法,我们可以让其递归到最末端,然后从尾巴到首部,依次给各个节点的height赋值。只需要遍历一遍。
以下是用递归实现的程序:

#include <iostream>

#define N 9			//请假装不知道N

using namespace std;

struct Node
{
    int height;
    Node* next;
};


Node* GetLinklist(void)			//构建一个N节点的链表
{
    Node* root = nullptr;
    Node* mid = nullptr;
    for(int i = 0; i < N; i++)
    {
        Node* temp = new Node;
        if(i == 0){
            root = temp;
            mid = temp;
        }
        else{
            mid->next = temp;
            mid = temp;
        }
    }
    mid->next = nullptr;
    return root;
}

void AssignData(Node* node)
{
    static int cnt = 0;					//cnt会被放在静态存储区,所以无论递归都少次,都只会被定义一次
    if(node == nullptr) return;			//递归结束的判断条件
    AssignData(node->next);				//自己调用自己,也是前向和后向的分界线
    //以下代码是从尾部到首部才会执行的
    node->height = cnt;
    cnt++;
}

int main()
{
    Node* root = GetLinklist();
    AssignData(root);
    return 0;
}

例子二:求一个二叉树的高度。二叉树的示意图如下:
在这里插入图片描述

分析:想要得到一棵树的高度,就得先得到其左子树和右子树的高度,再在两种中取得最大值。而为了得到左子树的高度,又得得到左左子树和左右子树的高度。。。如此套娃,直到最后一个节点。
于是,面对这样的套娃问题,不妨把一棵树多层次的树抽象为一个最简单的树,然后再使用递归去分别求得左右子树的高度。如图:
在这里插入图片描述

struct Node
{
    int data;
    Node* right;
    Node* left;
};

int get_height(Node* node)
{
    if(node == nullptr) return 0;
    return max(get_height(node->left), get_height(node->right)) + 1;
}

int main()
{
	Node* root = nullptr;			//假设root是一个多层树的根
	get_height(root);
	return 0;
}

即便如此,相比递归也不是很好理解。那不凡手动标出这个树的前向遍历顺序和反向遍历顺序。如图,黑色的是前向遍历的顺序,红色是反向遍历的顺序。而根据要求不同,我们即可以在函数调用自己之前写一些代码,让这些代码在前向遍历的时候执行。也可以在函数调用之后些一些代码,让代码在反向遍历的时候再执行。
在这里插入图片描述

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__TAT__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值