【二叉树】(一)递归遍历算法

前言

二叉树的遍历算法二叉树最基础的算法,没有之一。

二叉树的遍历算法主要有4种:先序遍历,中序遍历,后续遍历和层次遍历,其中第1-3个属于深度优先遍历,第4个属于广度优先遍历。

对二叉树的3种深度优先遍历算法的学习有三个层次:

(一)精通遍历算法的递归实现;

(二)精通遍历算法的基于栈结构的迭代实现;

(三)精通遍历算法的统一风格的递归实现。

我们希望读者至少可以掌握前两个层次。

本文讲解递归实现的深度优先遍历算法,使用C++和Python3分别进行演示。

一、二叉树节点的定义

现在假设我们已将0-9的10个数按顺序存储到了一棵完全二叉树中,其结构如下:

image.png

现在我们的树结点定义如下:

Python版本

class TreeNode:
    '''二叉树节点的定义'''
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = None
        self.right = None
以上Python代码将二叉树节点定义为Python类,这是因为Python类没有struct类型

C++版本

// 二叉树的节点
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

以上C++代码将二叉树节点定义为struct类型,并且给出了默认的构造函数

二、递归思想的要点

(一)递归程序的特点

递归在程序中指的就是在函数调用时调用函数自身

使用递归思想设计的程序一般代码简洁。 

但是递归程序在运行时是系统为每一层的返回点、局部变量等开辟了栈来存储,如果递归次数过多(常见于忘记设置递归程序的终止条件)容易造成栈溢出等,所以其运行效率也较低

(二)递归程序的设计

递归程序中的迭代函数的设计可以分为如下三个步骤:

(1)确定递归函数的参数和返回值

递归函数一定有参数传入作为初始值,返回值大概率有,最好添加上

(2)确定递归函数内部的终止条件

检查终止条件是进入递归函数中第一个要执行的逻辑,缺少一定会造成栈溢出。

(3)确定单层递归的逻辑

确定每⼀层递归需要处理的信息

(二)递归程序的举例

计算阶乘n! = 1 x 2 x 3 x ... x n,用Python3代码实现如下函数fact(n):

# (一)定义递归函数的参数和返回值
def fact(n:int)->int:
    result = 0
    # (二)检查终止条件
    if n==1:
        return 1
    # (三)递归调用函数
    result = n*fact(n-1)
    return result
想要计算100的阶乘,只需要执行fact(100)即可。

三、深度优先遍历的递归实现

因为每个复杂的二叉树都可以划分为左和右两个更加简单的二叉树

所以二叉树的很多算法天生具备递归性。

1、先序遍历

先序遍历的访问顺序是中间节点,左节点,右节点,即中左右。

本文二叉树的先序遍历结果是:0 1 3 7 8 4 9 2 5 6

(1)算法分析

我们可以设计一个递归函数来复杂处理一个最简单的二叉树。

该递归函数的输入参数至少有输入节点,返回值为该节点的值所在的结果数组;

终止条件是输入节点为空,则直接返回原有的结果数组;

递归调用就是给左节点调用函数自身,给右节点调用函数自身。

(2)算法实现

由于Python自带的List数据类型就可以提供栈的功能,所以我们直接使用列表来做为此处的栈。

C++版本

在C++版本中,我们在递归函数中前定义了一个全局结果列表,每次调用函数时处理中间节点值时添加进去:

    vector<int> result;
    vector<int> pre_order(TreeNode* root) {
        if(root==NULL){
            return result;
        }
        postorderTraversal(root->left);
        postorderTraversal(root->right);
        result.push_back(root->val);
        return result;
    }

 当然我们也可以给出其在一个函数中的版本:

void pre_order(TreeNode* cur, vector<int>& vec) {
         if (cur == NULL) return;
         vec.push_back(cur->val); // 中
         traversal(cur->left, vec); // 左
         traversal(cur->right, vec); // 右
     }

Python3版本

   result = []
    def pre_order(node:TreeNode):
        """先序遍历"""
        if node == None:
            return
        result.append(node.val)
        pre_order(node.left,result)
        pre_order(node.right,result)

或者

   def pre_order(self,node:TreeNode,result:List[int])->List[int]:
        """先序遍历"""
        if node == None:
            return result
        result.append(node.val)
        self.pre_order(node.left,result)
        self.pre_order(node.right,result)
        return result

 2、中序遍历

中序遍历的访问顺序是左节点,中间节点,右节点,即左中右。

本文二叉树的中序遍历结果是:7 3 8 1 9 4 0 5 2 6

直接给出算法实现

Python3版本

def in_order(node: TreeNode,result:List[int])->List[int]:
        """中序遍历"""
        if node == None:
            return result
        in_order(node.left,result)
        append(node.val)
        in_order(node.right,result)
        return result
    C++版本
    vector<int> result;	
	vector<int> inOrder(TreeNode* node) {
		if (node == NULL) {
			return result;
		}
		inOrder(node->left); // 左
		result.push_back(node->val); // 中
		inOrder(node->right); // 右 
        return result;
	}

3、后序遍历

后序遍历的访问顺序是左节点,右节点,中间节点,即左右中。

本文二叉树的后序遍历结果是:7 8 3 9 4 1 5 6 2 0

直接给出代码实现,如下:

Python3版本

def post_order(node: TreeNode,result:List[int])->List[int]:
        """后序遍历"""
        if node == None:
            return result
        post_order(node.left,result)
        post_order(node.right,result)
        result.append(node.val)
        return result
C++版本:
vector<int> result;	
	vector<int> postOrder(TreeNode* node) {
		if (node == NULL) {
			return result;
		}
		postOrder(node->left); // 左
		postOrder(node->right); // 右 
		result.push_back(node->val); // 中
        return result;
	}

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

魔法攻城狮MRL

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

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

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

打赏作者

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

抵扣说明:

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

余额充值