关于二叉树的三种遍历方式 Python实现

遍历二叉树的方案

一颗非空二叉树由根节点和左右子树三个部分构成,(NLR进行排序总共有6种方式,由于对称性问题,主要讨论三种)。

  • 先序遍历
    即先访问节点(Node)本身,然后访问左(left subtree)、右子树(right subtree)
  • 中序遍历
    即先访问左子树、然后再访问节点,最后访问节点。
  • 后序遍历
    先访问左子树、在访问右子树,最后访问节点。
    例图:
    在这里插入图片描述

1. 使用递归实现二叉树的遍历

  1. 构建二叉树
class Node:
    def __init__(self, value=None, left=None, right=None):
        self.value = value
        self.left = left # 左子树
        self.right = right # 右子树      
  1. 递归实现二叉树的前序、中序和后序遍历
# -*- coding: utf-8 -*-
class Node:
    def __init__(self,value=None,left=None, right=None):
        self.value = value
        self.left = left
        self.right = right

def preTraverse(root):
    # 前序遍历
    if root == None:
        return
    print(root.value, end=' ')
    preTraverse(root.left)
    preTraverse(root.right)

def midTraverse(root):
    # 中序遍历
    if root == None:
        return
    midTraverse(root.left)
    print(root.value, end=' ')
    midTraverse(root.right)

def afterTraverse(root):
    # 后序遍历
    if root == None:
        return
    afterTraverse(root.left)
    afterTraverse(root.right)
    print(root.value, end=' ')

# 测试:
if __name__ == '__main__':
    root = Node()
    root = Node('D', Node('B', Node('A'), Node('C')), Node('E', right=Node('G', Node('F'))))
    print('前序遍历:')
    preTraverse(root)
    print('\n中序遍历:')
    midTraverse(root)
    print('\n后序遍历:')
    afterTraverse(root)

运行结果:

“D:\Program Files\Anaconda3\python.exe” C:/Users/lenovo/Desktop/二叉树/BinaryTree.py
前序遍历:
D B A C E G F
中序遍历:
A B C D E F G
后序遍历:
A C B F G E D
Process finished with exit code 0

2. 使用栈实现二叉树的遍历

# # -*- coding: utf-8 -*-
class Node:
    def __init__(self, value=None, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right

    def preTraverse(self):
        """
        使用栈结构实现先序遍历的思路:先将该二叉树整体推入到栈中,
        根据栈后进先出的特性,先将栈取出:打印输出该二叉树的值,
        因此需要先将二叉树的右节点推入栈结构中(如果存在的话)
        然后再将二叉树的左节点推入栈中(如果存在的话)
        下一次从栈中取的话就能达到先去左节点,后取右节点的效果。
        """
        if self.value == None:
            return
        stack = [self]
        while stack:
            current = stack.pop()
            print(current.value, end=' ')
            if current.right:
                stack.append(current.right)
            if current.left:
                stack.append(current.left)

    def midTraverse(self):
        """
        中序遍历需要执行打印顺序为:左子树、节点、右子树
        需要先找到该二叉树的的最小左子树,然后从这颗左子树开始遍历节点和右子树
        """
        if self.value == None:
            return
        stack = []
        current = self
        while len(stack) != 0 or current:
            if current:  # 不断递进,直到找到当前树的最小左子树
                stack.append(current)
                current = current.left
            else:  # 当前的栈中末尾的树已经是最小树时
                temp = stack.pop()
                print(temp.value, end=' ')  # 打印出了当前树的节点后,开始对右子树动刀子
                current = temp.right

    def afterTraverse(self):
        if self.value == None:
            return
        stack1 = [self]
        stack2 = []
        #
        while stack1:  # 使用了两个栈进行存储,因此从两个栈就构成了一个队列,先进先出
            current = stack1.pop()
            stack2.append(current)
            if current.left:
                stack1.append(current.left)
            if current.right:
                stack1.append(current.right)
        # 直接遍历stack2输出即可:
        while stack2:
            print(stack2.pop().value, end=' ')

# 测试:
if __name__ == '__main__':
    root = Node('D', Node('B', Node('A'), Node('C')), Node('E', right=Node('G', Node('F'))))
    print('前序遍历:')
    root.preTraverse()
    print('\n中序遍历:')
    root.midTraverse()
    print('\n后序遍历:')
    root.afterTraverse()

输出结果与使用递归方式的结果相同。

3. 知其二遍历结果,如何求第三种?

3.1 已知前序和中序,如何还原二叉树?(已知中序和后序求前序类似)

  1. 由前序遍历的第一个可以确定根节点为D,通过对比中序遍历可以知道,左子树由ABC构成,右子树由EFG构成,但具体内容还得进一步分析;
  2. 同理左子树的前序遍历为BAC,中序遍历为ABC,可以确定该左子树的根节点为B,由中序遍历可知该节点的左子树为A,右子树为C。
  3. 同理对右子树的前序遍历为EGF,中序遍历为EFG,则可以确定右子树的根节点为E,右子树的左子树为空,右子树的右子树的根节点为G,其左子树为F。
    则可以还原出原来的树的结构,最后可以推出树的结构。
  4. 由于篇幅限制,基于上述3个步骤的演示:在知道了前序和中序还原了二叉树。

3.2 已知前序和中序,如何求解后序?

例如:

已知前序遍历:D B A C E G F
中序遍历:A B C D E F G
求后序遍历:
A C B F G E D
使用python代码实现:(递归求解)

pre = ['D','B','A','C','E','G','F']
mid = ['A','B','C','D','E','F','G']
def find_after(pre, mid):
    if not mid or not pre:
        return None
    troot = pre[0]
    for ind, item in enumerate(mid):
        if item == troot:
            break
    find_after(pre[1:ind+1], mid[:ind])
    find_after(pre[ind+1:], mid[ind+1:])
    print(troot, end=' ')
	
find_after(pre,mid)

注:该函数在求解长度为100000的二叉树数列(蓝桥杯算例):能够accept 91%的算例

3.3 已知中序和后序,如何求前序?

例如:

已知后序遍历:A C B F G E D
中序遍历:A B C D E F G
求前序遍历:
D B A C E G F

使用python代码实现:(递归求解)

mid = ['A','B','C','D','E','F','G']
after = ['A','C','B','F','G','E','D']
def find_pre(mid,after):
    if not after or not mid:
        return None
    troot = after[-1]
    for ind, item in enumerate(mid):
        if item == troot:
            break
    print(troot,end=' ')
    find_pre(mid[:ind],after[:ind])
    find_pre(mid[ind+1:],after[ind:-1])

find_pre(mid,after)

3.4 已知前序和后序,如何求中序的结果?

由于知道前序和后序,不能得到唯一确定的二叉树,此处将不再讨论。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值