二叉树各种遍历(leetcode上试题总结,附链接)

本文深入探讨了二叉树和N叉树的前序遍历、中序遍历、后序遍历、层次遍历等操作,详细解释了递归和非递归方法,并通过实例代码展示了具体实现。同时,涵盖了二叉树的垂序遍历和展开为链表的算法,全面解析了这些遍历方法的逻辑和技巧。
摘要由CSDN通过智能技术生成


python 用append + pop模拟栈,用append + pop(0) 模拟队列

二叉树的前中后三种遍历方式分别对应根节点输出位置,前序遍历即根节点最先输出,根左右。中序遍历为根节点在中间输出,左根右。后序遍历为根节点最后输出,左右根。
这三种遍历方式均为深度优先遍历,即其遍历方式均为遍历完树的一个分支,再遍历另一个分支,而不是先遍历完一层再遍历另一层。
深度优先遍历,为从当前节点,沿着一个方向逐步探索,当前节点的另一个方向还并未被探索。因此当前节点不能直接出结构体,其需要等待其下所有节点都被探索完,都出结构体后才能出结构体,因此深度优先遍历选用后进先出结构体“栈”。

1. 前序遍历

根左右

a. 二叉树前序遍历

https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
遍历过程为下图,蓝色为正在遍历节点,红色为已经被遍历过的节点。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


1)递归法
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

#  前序遍历:根左右
'''  1. 递归法,很简单,根节点append进list,递归左节点,递归右节点
class Solution(object):
    def preorder(self, root, result):
        result.append(root.val)
        if root.left:
            self.preorder(root.left, result)
        if root.right:
            self.preorder(root.right, result)
        return result

    def preorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = list()
        if root is None:
            return result
        self.preorder(root, result)
        return result
'''

2)非递归

栈顶出栈,栈顶右节点入栈,栈顶左节点入栈,重复过程,直到栈空。
蓝色为入栈节点,红色为已出栈节点。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

''' 
2. 迭代法  根左右
    深度优先遍历,用栈          
    期待出栈顺序为 (即遍历顺序)
	根左右
    则操作的顺序为 
    根入栈 -- 根出栈 -- 右子节点入栈 -- 左子节点入栈 -- 左子节点出栈 -- 右子节点出栈
'''
    
class Solution(object):
    def preorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = list()
        if root is None:
            return result
        tree = list()
        tree.append(root)
        while len(tree) != 0:
            node = tree.pop()
            result.append(node.val)
            if node.right:
                tree.append(node.right)
            if node.left:
                tree.append(node.left)
        return result

在这里插入图片描述

b. N叉树前序遍历

https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/
和二叉树没有太大区别,就是二叉树就是左右子节点,n叉树要循环所有children


1)递归法
"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

''' 1. 递归法
class Solution(object):
    def pre(self, root, result):
        result.append(root.val)
        for node in root.children:
            if node is not None:
                self.pre(node, result)
        return

    def preorder(self, root):
        """
        :type root: Node
        :rtype: List[int]
        """
        result = list()
        if root is None:
            return result
        self.pre(root, result)
        return result
'''

2)非递归
''' 2. 迭代法  出栈顶,从children尾开始入栈,以便可以从children头开始出栈  '''
class Solution(object):
    def preorder(self, root):
        """
        :type root: Node
        :rtype: List[int]
        """
        result = list()
        if root is None:
            return result
        tree = list()
        tree.append(root)
        while len(tree) != 0:
            node = tree.pop()
            result.append(node.val)
            for i in range(1, len(node.children)+1):
                tmp = node.children[-i]
                if tmp is not None:
                    tree.append(node.children[-i])
        return result

2. 中序遍历

左根右

a. 二叉树的中序遍历

https://leetcode-cn.com/problems/binary-tree-inorder-traversal/
蓝色为正在遍历的节点,红色为已经遍历过的节点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


1)递归法
# 1. 递归法 递归左节点,result append根节点,递归右节点 
class Solution(object):
    def inorder(self, root, result):
        if root.left:
            self.inorder(root.left, result)
        result.append(root.val)
        if root.right:
            self.inorder(root.right, result)
        return
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = list()
        if root is None:
            return result
        self.inorder(root, result)
        return result

2)非递归

蓝色为入栈节点,红色为已出栈节点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right


''' 2. 迭代法 
    期待出栈顺序为
    左根右
    则其操作顺序为
    根入栈 -- (根左节点入栈 -- 根左节点左节点入栈,直到没有左节点 -- 栈顶出栈(左节点))
                    -- 栈顶有右节点,右节点入栈,重复前面括号中过程
                    -- 栈顶没有右节点,接着出栈,直到出栈元素有右节点,或栈已出空
'''
class Solution(object):
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = list()
        if root is None:
            return result
        tree = list()
        cur = root
        while len(tree) != 0 or cur is not None:
            if cur is not None:
                tree.append(cur)
                cur = cur.left
            else:
                node = tree.pop()
                result.append(node.val)
                cur = node.right
            
        return result


递归反而更快一些,应该是栈方法节点都需要遍历两遍的原因吧
在这里插入图片描述

3. 后序遍历

a. 二叉树的后序遍历

左右根
https://leetcode-cn.com/problems/binary-tree-postorder-traversal/
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


1)递归法
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def postorder(self, root, result):
        if root is None:
            return
        if root.left:
            self.postorder(root.left, result)
        if root.right:
            self.postorder(root.right, result)
        result.append(root.val)
        return
    def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = list()
        self.postorder(root, result)
        return result

2)非递归

蓝色为入栈节点,红色为已出栈节点
注意后序遍历与前序和中序遍历不同,前序和中序遍历是沿着当前路径向下探寻,当发现没有新节点可以入栈,则栈顶出栈,并以栈顶为新的根节点,接着向下探寻。但是后序遍历,当当前路径探寻到尽头,栈顶元素不能直接出栈,需要判断栈顶元素是否有另一个未被遍历子节点,若存在未被遍历子节点,则该子节点入栈。当栈顶元素所有子节点被遍历完成,栈顶元素出栈。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
难点在于需要判断该节点左右节点均被遍历后,该节点才能出栈。

a)标记法

节点p入栈,左节点入栈,左子树遍历完,右节点入栈,右节点遍历完,节点p出栈。则用mark标记刚刚出栈的元素,如果其为当前栈顶元素的右节点,代表当前栈顶元素左右节点均被遍历,可以出栈。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    '''
    迭代法
    预期出栈顺序为 左右根
    操作为 根入栈 -- 左节点入栈 -- 左节点入栈,直到没有左节点 
                -- 栈顶元素有右节点,栈顶元素不出栈,右节点入栈
                -- 栈顶元素没有右节点,则当前栈顶元素左右节点,均遍历完,当前栈顶元素出栈
    用mark标记刚刚出栈的栈顶元素,如果mark为当前栈顶元素右节点,代表当前栈顶元素左右节点均被遍历,当前栈顶元素可以出栈,如果不是,入栈其右节点
    '''
    def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = list()
        if root is None:
            return result
        tree = list()
        mark = None
        tree.append(root)
        node = root.left
        while len(tree) != 0:
            while node:
                tree.append(node)
                node = node.left
            mark = None
            while len(tree) != 0: 
                node = tree.pop(-1)
                if node.right == mark:   # 从右子节点遍历回来,可以出栈了
                    result.append(node.val)
                    mark = node
                else:                    # 从左子节点遍历过来,入右子节点,重复整个遍历过程
                    tree.append(node)
                    node = node.right
                    break
        return result


b)颠倒输出

后序遍历的输出顺序为 左 – 右 – 根,根 – 右 – 左。则设定出栈顺序为 根 – 右 – 左,入栈顺序 根入栈 – 根出栈 – 左节点入栈 – 右节点入栈。之后再颠倒回来即可。

class Solution(object):
    def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = list()
        if root is None:
            return result
        tree = list()
        tree.append(root)
        while len(tree) != 0:
            node = tree.pop()
            if node.left:
                tree.append(node.left)
            if node.right:
                tree.append(node.right)
            result.append(node.val)
        return result[::-1]

b. N叉树的后序遍历


1)递归法
"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution(object):
    def inpostorder(self, root, result):
        if root is None:
            return result
        for node in root.children:
            if node:
                self.inpostorder(node, result)
        result.append(root.val)
        return result
    def postorder(self, root):
        """
        :type root: Node
        :rtype: List[int]
        """
        result = list()
        if not root:
            return result
        self.inpostorder(root, result)
        return result

2)非递归
"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution(object):
    # 颠倒输出
    def postorder(self, root):
        """
        :type root: Node
        :rtype: List[int]
        """
        result = list()
        if not root:
            return result
        tree = list()
        tree.append(root)
        while len(tree) != 0:
            node = tree.pop()
            for tmp in node.children:
                if tmp:
                    tree.append(tmp)
            result.append(node.val)
        return result[::-1]

4. 层次遍历

树的层次遍历是先遍历完当前层,再遍历下一层,属于广度优先遍历。不同于深度优先遍历,广度优先遍历为遍历完当前节点的左右子节点,再去遍历下一个节点,因此,当前节点遍历完后可出结构体,用队列来实现。

a. 二叉树层次遍历

1)二叉树层次遍历I

https://leetcode-cn.com/problems/binary-tree-level-order-traversal/
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
实现过程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
因为题中要求每层为一个list,append到结果中,因此需要用一个count变量,记录每层的节点数。每pop一个节点,则当前层node数减一,当count==0,代表当前层遍历完成,当前层结果level append 到result中,进行下一层遍历。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        result = list()
        if root is None:
            return result
        tree = list()
        tree.append(root)
        level = list()
        while len(tree) != 0:
            count = len(tree)   # 记录当前层节点数,遍历完当前层后,将当前层结果append到result中
            while count != 0:
                node = tree.pop(0)
                count -= 1
                if node.left:
                    tree.append(node.left)
                if node.right:
                    tree.append(node.right)
                level.append(node.val)
            result.append(level)
            level = list()
        return result
2)二叉树层次遍历II

https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/
本题要求的遍历顺序为,自底向上。基本和上一题相同,只是上一题没遍历完一层为往列表尾部追加元素,本题遍历完一层,为往链表头部追加。python像list头部追加元素的函数为list.insert(0,’’)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def levelOrderBottom(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        result = list()
        if root is None:
             return result
        tree = list()
        tree.append(root)
        level = list()
        while len(tree) != 0:
            count = len(tree)
            while count != 0:
                node = tree.pop(0)
                count -= 1
                if node.left:
                    tree.append(node.left)
                if node.right:
                    tree.append(node.right)
                level.append(node.val)
            result.insert(0, level)   # 这里把append换成insert
            level = list()
        return result
3)二叉树的锯齿形层序遍历

https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/
以上两道题为每层遍历都是从左向右遍历,本题为第一层为从左向右遍历,则第二层为从右向左遍历,第三层为从左向右遍历,依次替换。则为从0开始算,偶数层从左向右,奇数层从右向左。添加一个记录当前层为奇偶的标志位,偶数层每遍历一个元素,往level尾部追加,奇数层每遍历一个元素,往level头部插入,即可。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def zigzagLevelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        result = list()
        if root is None:
            return result
        tree = list()
        level = list()
        tree.append(root)
        flag = 0   # 标记当前层奇偶
        while len(tree) != 0:
            count = len(tree)
            while count != 0:
                node = tree.pop(0)
                count -= 1
                if node.left:
                    tree.append(node.left)
                if node.right:
                    tree.append(node.right)
                if flag:     # 根据奇偶层决定是加在队列头还是队列尾
                    level.insert(0, node.val)
                else:
                    level.append(node.val)
            result.append(level)
            level = list()
            flag = 1 - flag
        return result

b. N叉树层次遍历

https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/

"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution(object):
    def levelOrder(self, root):
        """
        :type root: Node
        :rtype: List[List[int]]
        """
        result = list()
        if root is None:
            return result
        tree = list()
        tree.append(root)
        level = list()
        while len(tree) != 0:
            count = len(tree)
            while count != 0:
                node = tree.pop(0)
                count -= 1
                for tmp in node.children:
                    tree.append(tmp)
                level.append(node.val)
            result.append(level)
            level = list()
        return result

5. 二叉树垂序遍历(hard)

https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree/
给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列。
对位于 (row, col) 的每个结点而言,其左右子结点分别位于 (row + 1, col - 1) 和 (row + 1, col + 1) 。树的根结点位于 (0, 0) 。
二叉树的 垂序遍历 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,则按结点的值从小到大进行排序。
返回二叉树的 垂序遍历 序列。
在这里插入图片描述
在这里插入图片描述

思路:先遍历,得到每个节点的坐标。存储结构为以坐标为key的dict。遍历完树之后,按坐标排序,对节点进行输出。感觉难度算不上hard。


class Solution(object):
   def dfs(self, root, result, x, y):
       if root is None:
           return result
       if (x, y) in result:
           result[(x, y)].append(root.val)
       else:
           result[(x, y)] = [root.val]
       if root.left:   # 左子节点,坐标x-1,y+1
           self.dfs(root.left, result, x-1, y+1)
       if root.right:  # 右子节点,坐标x+1,y+1
           self.dfs(root.right, result, x+1, y+1)
       return result
   def verticalTraversal(self, root):
       """
       :type root: TreeNode
       :rtype: List[List[int]]
       """
       re = list()
       result = dict()
       if root is None:
           return result
       self.dfs(root, result, 0, 0)
       # 此时result中为坐标对应的val,譬如[3,9,20,null,null,15,7],
       # result为 {(2, 2): [7], (-1, 1): [9], (0, 0): [3], (1, 1): [20], (0, 2): [15]}
       # 按(x,y)进行排序
       sorted_result = sorted(result.items(), key=lambda item: item[0])
       level = list()
       same_item = list()
       pre_x = 'x'
       for item in sorted_result:
           x = item[0][0]
           value = item[1]
           if x != pre_x:
               if pre_x != 'x':   # 换列,将当前列内容append到re中
                   re.append(level)
               level = list()
               pre_x = x
           for tmp in sorted(value):  # 相同坐标位进行排序
               level.append(tmp)  
       re.append(level)
       return re

6. 二叉树展开为链表

https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/
给你二叉树的根结点 root ,请你将它展开为一个单链表:

展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
展开后的单链表应该与二叉树 先序遍历 顺序相同。
在这里插入图片描述
注意题里要求不需要返回,直接在原地进行修改

a. 暴力法

思路:由于展开后单链表为与二叉树先序遍历顺序相同,则先先序遍历二叉树,得到结果队列。再根据结果队列,重建链表树。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def dfs(self, root, result):
        if root is None:
            return result
        result.append(root.val)
        if root.left:
            self.dfs(root.left, result)
        if root.right:
            self.dfs(root.right, result)
        return result

    def flatten(self, root):
        """
        :type root: TreeNode
        :rtype: None Do not return anything, modify root in-place instead.
        """
        result = list()
        if root is None:
            return result
        self.dfs(root, result)
        node = root
        for i in range(1, len(result)):
            node.left = None
            node.right = TreeNode(result[i])
            node = node.right
        return

b. 前序遍历和展开同步

思路:展开后树的结构为
在这里插入图片描述
则与前序非递归遍历操作相似
根入栈 – 根出栈 – 右子节点入栈 – 左子节点入栈 – 根左节点置为null – 根右节点置为当前栈顶,即刚刚入栈的左节点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def flatten(self, root):
        """
        :type root: TreeNode
        :rtype: None Do not return anything, modify root in-place instead.
        """
        result = list()
        if root is None:
            return result
        tree = list()
        tree.append(root)
        while len(tree) != 0:
            node = tree.pop()
            if node.right:
                tree.append(node.right)
            if node.left:
                tree.append(node.left)
            if len(tree) != 0:
                node.left = None
                node.right = tree[-1]
        return


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值