跳转至

二叉树遍历

二叉树定义

二叉树的父节点最多有2个子节点,如果二叉树的所有父节点没有节点或者有2个节点,那么叫完全二叉树

二叉树的遍历方式

二叉树有4中遍历方式: 前序遍历, 中序, 后序, 以及层序

前三种可以对比着看,区别在于父节点先被访问的顺序,这里的先后都是相对于同一个树而言。 这里的访问意思是访问其值, 例如打印节点的数据:
* 前序遍历, 先父节点,再左子节点,最后是右子节点 * 中序遍历, 先左子节点, 再父节点, 最后是右子节点 * 中序遍历, 先左子节点, 再右子节点 ,最后父节点

可见,都是先左子节点后右子节点

而层序遍历是从上往下,广度优先

效果

若有以下二叉树,则遍历结果

graph BT
    A[1] --> B[0]
    C[2] --> B
    D[3] --> A
    E[4] --> A
    F[5] --> C
    G[6] --> C
    H[7] --> D
    I[8] --> D
    J[9] --> E

层序: 0 1 2 3 4 5 6 7 8 9

先序: 0 1 3 7 8 4 9 2 5 6
中序: 7 3 8 1 9 4 0 5 2 6
后序: 7 8 3 9 4 1 5 6 2 0

注意下划线,即036组成的一个树, 可以证实上面的总结

代码实现

实现前三种遍历都有2种方式, 递归和使用stack

节点数据结构

    def Node:
        self.item
        self.lchild
        self.rchild

递归实现

前序遍历

def front_recursion(root: Node):
    if root is None:
        return None
    print(root.item)
    if root.lchild is not None:
        front_recursion(root.lchild)
    if root.rchild is not None:
        front_recursion(root.rchild)

中序遍历

def Middle_recursion(root: Node):
    if root is None:
        return None
    if root.lchild is not None:
        front_recursion(root.lchild)
    print(root.item)
    if root.rchild is not None:
        front_recursion(root.rchild)

后序遍历

def Middle_recursion(root: Node):
    if root is None:
        return None
    if root.lchild is not None:
        front_recursion(root.lchild)
    if root.rchild is not None:
        front_recursion(root.rchild)
    print(root.item)

stack实现

前序遍历

def Front_stack(root: Node):
    if root is None:
        return None

    stack = []
    Node = root
    stack.append(Node)

    while Node or stack:
        while Node:
            # 访问和入栈的顺序顺序是先父节点后左节点
            print(Node.item)
            # 父节点入栈
            stack.append(Node.lchild)
            # 深度优先,找最左节点,下个循环就是先访问父节点后左子节点
            Node = Node.lchild
        # 这里需要好好体会,父节点和左子节点已经访问过,只剩下右节点
        # 所以就是先左后右
        Node = stack.pop()
        Node = Node.rchild

中序遍历

def Middle_stack(root: Node):
    if root is None:
        return None

    stack = []
    Node = root
    stack.append(Node)

    while Node or stack:
        while Node:
            # 父节点入栈
            # 左子节点入栈
            # 但都不访问,因为压栈顺序是先父后左子,到出栈的时候再访问
            stack.append(Node.lchild)
            Node = Node.lchild

        Node = stack.pop()
        # 找到最左子节点了,开始出栈,所以肯定是先出左节点, 然后再出栈之后就是父节点
        print(Node.item)
        # 最后就是右节点, 回到第一个while 继续找右子树的最左节点
        Node = Node.rchild

后序的stack比较复杂

还有一个比较简单的先序stack

def Front_stack(root: Node):
    if root is None:
        return None

    stack = []
    stack.append(root)

    while stack:
        Node = stack.pop()
        print(Node.item)

        # stack 先进后出,所以先压右节点
        if Node.rchild is not None:
            stack.append(Node.rchild)

        if Node.lchild is not None:
            stack.append(Node.lchild)

层序遍历,是广度优先的一种方式,所以使用到queue

def Layer_queue(root: Node):
    if root is None:
        return None

    queue = []
    queue.append(root)
    while queue:
        # 取前面的
        Node = queue.pop(0)
        print(Node.item)
        if Node.lchild is not None:
            queue.append(Node.lchild)

        if Node.rchild is not None:
            queue.append(Node.rchild)

后序栈遍历

后序遍历的顺序是先左子后右子,最后才是父节点

'''
1. 同样先找到最左边的节点,父节点和左子节点入栈
2. 找到最后一个左子节点之后,判断栈顶的节点,出栈顺序是先左子后父节点,所以只需要判断右子节点的情况:
   如果栈顶节点的右子节点为空,直接打印栈顶节点。 如果栈顶节点的右子节点是上一个出栈的节点,那么说明已经访问到了右子节点,可以继续打印父节点  
   如果栈顶的右子节点不为空也不是上一个访问的节点,所以要先去访问右子树, 将右子节点入栈,退出循环,执行第一步
'''
def back_stack(self, root):
    if root is None:
        return None
    stack = []
    Tag = None
    stack.append(root)
    while stack:
        Node = stack[-1]
        while Node.lchild:
            stack.append(Node.lchild)
            Node = Node.lchild

        while stack:
            Node = stack[-1]
            if Tag == Node.rchild or Node.rchild is None:
                Node = stack.pop()
                print(Node.item)
                Tag = Node
            elif Node.rchild is not None:
                stack.append(Node.rchild)
                break