二叉树的遍历


本期我们聊一聊二叉树的遍历。
在讲堆排序的时候,已经为大家讲解了树的基本知识,不了解的同学可以去看一下堆排序的文章,在这里就不再赘述了。那么首先先画一棵简单的二叉树:
****
然后我们用代码实现这棵二叉树:

class BitreeNode:  
    def __init__(self, data):  
        self.data = data  
        self.lchild = None  
        self.rchild = None  


a = BitreeNode("A")  
b = BitreeNode("B")  
c = BitreeNode("C")  
d = BitreeNode("D")  
e = BitreeNode("E")  
f = BitreeNode("F")  
g = BitreeNode("G")  

e.lchild = a  
e.rchild = g  
a.rchild = c  
c.lchild = b  
c.rchild = d  
g.rchild = f

那么,首先先给大家三种遍历的结果,大家根据遍历的结果,看看是否能推断出是如何进行遍历的。
前序遍历:E A C B D G F
中序遍历:A B C D E G F
后序遍历:B D C A F G E
其实大家根据结果与遍历名称其实也可以大致推断出遍历方式,我们假设有一个列表存取每次的结果,首先我们先来看前序遍历:所谓前序遍历,就是从根节点处开始,先找左子节点后找右子节点并不断递归的过程,以本文样例为例,从E开始,E进列表,找到左子节点A,A进列表,然后找A的左子节点发现没有,然后找A的右子节点C,C进列表,然后找C的左子节点B,找B的左子节点发现没有,找B的右子节点也没有,返回C,找到C的右子节点D,D进列表,D同B一样没有左右子节点,返回C,C均找过返回A,A返回E,找E的右子节点G,G进列表,找G左子节点没有找右子节点F,F进列表,找F没有左右子节点返回G,G返回E 结束。
整个过程的图示为:
****
从图示中我们可以看到,先将根节点放在队首,然后向后的两个空间存放左右两个新子树,然后新的子树再将根节点放在第一位,以此类推。我们来看一下代码实现:

def prev_order(root):  
    if root:  
        print(root.data, end=" ")  
        prev_order(root.lchild)  
        prev_order(root.rchild)

接下来是中序遍历,所谓中序遍历,就是先遍历左子树再遍历根节点最后遍历右子树,以图为例,先遍历E的左子树(A C B D),然后找到根节点 A 遍历其左右子树,没有左子树,返回A,A进列表,遍历右子树(C B D),找到其根节点C遍历左子树B,B没有左子树,返回B,B进列表,B也没有右子树,返回C,C进列表,遍历C的右子树D,D没有左子树,返回D,D进列表,也没有右子树,证明左子树遍历结束,返回E,E进列表,然后遍历E的右子树,方法同上,先返回G,再返回F。
整个过程的图示为:
****
由图示我们可以看到,先将根节点放于中间,左右两边各开辟一个空间分别存放左右子树,然后左子树内将新根节点放于中间,左右各开辟新空间存放新的左右子树,右子树同理。代码实现如下:

def mid_order(root):  
    if root:  
        mid_order(root.lchild)  
        print(root.data, end=" ")  
        mid_order(root.rchild)

最后是后序遍历,所谓后续遍历,大家已经可以根据刚刚两个所讲的遍历方式推断出是如何遍历的了,就是先遍历左子树,再遍历右子树,最后回到根节点,以图为例,我们已知E是根节点,先观察左子树(A C B D),然后找到新根节点A,找其左子树发现没有,然后找其右子树(C B D),然后找到新根节点C,找其左子树B,发现没有左右子树后,返回B,B进列表,然后找C的右子树D,没有左右子树,返回D,D进列表,返回C,C进列表,然后返回A,A进列表,以A为根节点的左子树遍历完成,用同样的方法遍历E的右子树(G F),最后返回E。
整个过程图示为:
****
由图示我们可以看到,先将根节点放于尾部,然后前面开辟一前一后两个空间分别存放左子树右子树,然后方法同样,递归实现:

def post_order(root):  
    if root:  
        post_order(root.lchild)  
        post_order(root.rchild)  
        print(root.data, end=" ")

最后,跟大家聊一聊根据遍历结果复原树的方法,这个时候,我们需要以下两种条件:

  1. 前序遍历 + 中序遍历
  2. 中序遍历 + 后序遍历

注意,这两个条件中我们都看到了中序遍历,中序充当了胶水的重要角色,那么如何实现呢,给大家模拟一下,
首先,我们观察到前序遍历的第一个字母E,证明整个树的根节点是E,然后我们观察中序遍历,找到E,那么E的两端就分别是其左子树(A B C D)和右子树(G F)了。这个时候,我们就可以把E画在纸上了,然后看前序遍历,找到左子树的四个元素,A是第一个,证明A是此左子树的根节点,然后再回到中序遍历找这个左子树,发现A左面是没有元素的,证明A是没有左子树的,同时A的右子树就是(B C D),然后再先到前序遍历中找到C,然后回到中序遍历中找到C的左右两端,以此类推,我们是不是就能画出E的左子树:
****
那么按照同样的方式,是不是就可以也可以画出E的右子树。
那么中序遍历 + 后续遍历的寻找方式是不是也是一样的呢?大家自己做一做,有不会的地方,欢迎在评论区里留言。


文章作者: Runze_Li
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Runze_Li !