前言
二叉树的遍历算法是二叉树最基础的算法,没有之一。
二叉树的遍历算法主要有4种:先序遍历,中序遍历,后续遍历和层次遍历,其中第1-3个属于深度优先遍历,第4个属于广度优先遍历。
对二叉树的3种深度优先遍历算法的学习有三个层次:
(一)精通遍历算法的递归实现;
(二)精通遍历算法的基于栈结构的迭代实现;
(三)精通遍历算法的统一风格的递归实现。
我们希望读者至少可以掌握前两个层次。
本文讲解递归实现的深度优先遍历算法,使用C++和Python3分别进行演示。
一、二叉树节点的定义
现在假设我们已将0-9的10个数按顺序存储到了一棵完全二叉树中,其结构如下:
现在我们的树结点定义如下:
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;
}