二叉树的遍历

所谓二叉树的遍历,就是把二叉树的所有树节点依次输出,每个节点只输出一次,且所有节点都被输出。我们常见的遍历方式一共是四种:前序遍历,中序遍历,后序遍历,以及层次遍历。概念上,前三种一般被称为深度优先遍历(与深度优先搜索的逻辑是一致的,关于深度优先搜索详见:点击打开链接),而层次遍历一般被称为广度优先遍历。在lintcode上,就这四种方法,就分别有一道题目与之对应。当然,题目永远是次要,通过题目理解二叉树的构造,学习深搜程序的基本写作流程,才是我们应该学习的重点。

先说深度优先遍历。前序遍历,中序遍历,后序遍历,不同之处在于输出节点的顺序,具体的:
1. 前序(pre-order):先根后左再右
2. 中序(in-order):先左后根再右
3. 后序(post-order):先左后右再根

下面这幅图就特别形象了:


好吧,我承认我是截图的,别人给的很全,最后也给出了层次遍历的顺序(这个先不说)。举例前序遍历,也就是说对扫描到的每一个节点都采取先输出他自己,再扫描左孩子(对左孩子一样使用前序遍历),再扫描右孩子(同理,对右孩子前序遍历)。这就不用说是什么逻辑了吧——当然是我们说过无数遍的递归。中序、后序也是同理。

因此,用递归能非常简单的写出三种遍历方式的代码:

# preorder
def preorderTraversal(root):
    if root is None:
        return []
    return [root.val] + preorderTraversal(root.left) + preorderTraversal(root.right)


# inorder
def inorderTraversal(root):
    if root is None:
        return []
    return inorderTraversal(root.left) + [root.val] + inorderTraversal(root.right)


# postorder
def postorderTraversal(root):
    if root is None:
        return []
    return postorderTraversal(root.left) + postorderTraversal(root.right) + [root.val]

递归的思想不多做解释了,这个逻辑就跟自然语言的描述是一样的(Python更接近这种自然描述)。需要注意的一点是“触底”后程序的反应,因为这里没有设置全局变量,所以返回的是一个空列表。这个空列表是要参与到之后“回溯”的运算中的。但是,如果设置了一个全局变量存储输出的节点值,“触底”的做法就不一样了。类似于我们在“二叉树的所有路径中”使用的递归算法,要求“触底”时直接return(也就是什么都不做)。


所以,程序也可以写成这种形式:

# result = []
# postorderTraversal(root, result)
# print(result)


def postorderTraversal(root, result):
    if root is None:
        return
    postorderTraversal(root.left, result)
    postorderTraversal(root.right, result)
    result.append(root.val)


这里定义的后序遍历函数其实是改变了列表result,所以什么都不返回(相当于C++中的void函数)。“触底”的条件依然是节点为空,此时,“触底”后,什么都不做。运行程序时可执行最上边的注释给出的三行代码,即可看到输出结果。

然而,“递归虽易,面试却难”。递归算法由于其效率方面的天然缺点,并不受面试官欢迎。我们一般使用迭代来实现遍历。这个以后会讲解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值