今天是大自然的搬运工

Definition for a binary tree node.

class TreeNode:

def init(self, x):

self.val = x

self.left = None

self.right = None

递归

时间复杂度:O(n),n为节点数,访问每个节点恰好一次。

空间复杂度:空间复杂度:O(h),h为树的高度。最坏情况下需要空间O(n),平均情况为O(logn)

递归1:二叉树遍历最易理解和实现版本

class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
# 前序递归
return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)
# # 中序递归
# return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right)
# # 后序递归
# return self.postorderTraversal(root.left) + self.postorderTraversal(root.right) + [root.val]

递归2:通用模板,可以适应不同的题目,添加参数、增加返回条件、修改进入递归条件、自定义返回值

class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
def dfs(cur):
if not cur:
return
# 前序递归
res.append(cur.val)
dfs(cur.left)
dfs(cur.right)
# # 中序递归
# dfs(cur.left)
# res.append(cur.val)
# dfs(cur.right)
# # 后序递归
# dfs(cur.left)
# dfs(cur.right)
# res.append(cur.val)
res = []
dfs(root)
return res

迭代

时间复杂度:O(n),n为节点数,访问每个节点恰好一次。

空间复杂度:O(h),h为树的高度。取决于树的结构,最坏情况存储整棵树,即O(n)

迭代1:前序遍历最常用模板(后序同样可以用)

class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
res = []
stack = [root]
# # 前序迭代模板:最常用的二叉树DFS迭代遍历模板
while stack:
cur = stack.pop()
res.append(cur.val)
if cur.right:
stack.append(cur.right)
if cur.left:
stack.append(cur.left)
return res

    # # 后序迭代,相同模板:将前序迭代进栈顺序稍作修改,最后得到的结果反转
    # while stack:
    #     cur = stack.pop()
    #     if cur.left:
    #         stack.append(cur.left)
    #     if cur.right:
    #         stack.append(cur.right)
    #     res.append(cur.val)
    # return res[::-1]

迭代1:层序遍历最常用模板

class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
cur, res = [root], []
while cur:
lay, layval = [], []
for node in cur:
layval.append(node.val)
if node.left: lay.append(node.left)
if node.right: lay.append(node.right)
cur = lay
res.append(layval)
return res

迭代2:前、中、后序遍历通用模板(只需一个栈的空间)

class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
res = []
stack = []
cur = root
# 中序,模板:先用指针找到每颗子树的最左下角,然后进行进出栈操作
while stack or cur:
while cur:
stack.append(cur)
cur = cur.left
cur = stack.pop()
res.append(cur.val)
cur = cur.right
return res

    # # 前序,相同模板
    # while stack or cur:
    #     while cur:
    #         res.append(cur.val)
    #         stack.append(cur)
    #         cur = cur.left
    #     cur = stack.pop()
    #     cur = cur.right
    # return res
    
    # # 后序,相同模板
    # while stack or cur:
    #     while cur:
    #         res.append(cur.val)
    #         stack.append(cur)
    #         cur = cur.right
    #     cur = stack.pop()
    #     cur = cur.left
    # return res[::-1]

迭代3:标记法迭代(需要双倍的空间来存储访问状态):

前、中、后、层序通用模板,只需改变进栈顺序或即可实现前后中序遍历,

而层序遍历则使用队列先进先出。0表示当前未访问,1表示已访问。

class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
res = []
stack = [(0, root)]
while stack:
flag, cur = stack.pop()
if not cur: continue
if flag == 0:
# 前序,标记法
stack.append((0, cur.right))
stack.append((0, cur.left))
stack.append((1, cur))

            # # 后序,标记法
            # stack.append((1, cur))
            # stack.append((0, cur.right))
            # stack.append((0, cur.left))
            
            # # 中序,标记法
            # stack.append((0, cur.right))
            # stack.append((1, cur))
            # stack.append((0, cur.left))  
        else:
            res.append(cur.val)  
    return res
    
    # # 层序,标记法
    # res = []
    # queue = [(0, root)]
    # while queue:
    #     flag, cur = queue.pop(0)  # 注意是队列,先进先出
    #     if not cur: continue
    #     if flag == 0:
              # 层序遍历这三个的顺序无所谓,因为是队列,只弹出队首元素
    #         queue.append((1, cur))
    #         queue.append((0, cur.left))
    #         queue.append((0, cur.right))
    #     else:
    #         res.append(cur.val)
    # return res

莫里斯遍历

时间复杂度:O(n),n为节点数,看似超过O(n),有的节点可能要访问两次,实际分析还是O(n),具体参考大佬博客的分析。

空间复杂度:O(1),如果在遍历过程中就输出节点值,则只需常数空间就能得到中序遍历结果,空间只需两个指针。

如果将结果储存最后输出,则空间复杂度还是O(n)。

PS:莫里斯遍历实际上是在原有二叉树的结构基础上,构造了线索二叉树,

线索二叉树定义为:原本为空的右子节点指向了中序遍历顺序之后的那个节点,把所有原本为空的左子节点都指向了中序遍历之前的那个节点

emmmm,好像大学教材学过,还考过

此处只给出中序遍历,前序遍历只需修改输出顺序即可

而后序遍历,由于遍历是从根开始的,而线索二叉树是将为空的左右子节点连接到相应的顺序上,使其能够按照相应准则输出

但是后序遍历的根节点却已经没有额外的空间来标记自己下一个应该访问的节点,

所以这里需要建立一个临时节点dump,令其左孩子是root。并且还需要一个子过程,就是倒序输出某两个节点之间路径上的各个节点。

具体参考大佬博客

莫里斯遍历,借助线索二叉树中序遍历(附前序遍历)

class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
res = []
# cur = pre = TreeNode(None)
cur = root

    while cur:
        if not cur.left:
            res.append(cur.val)
            # print(cur.val)
            cur = cur.right
        else:
            pre = cur.left
            while pre.right and pre.right != cur:
                pre = pre.right
            if not pre.right:
                # print(cur.val) 这里是前序遍历的代码,前序与中序的唯一差别,只是输出顺序不同
                pre.right = cur
                cur = cur.left
            else:
                pre.right = None
                res.append(cur.val)
                # print(cur.val)
                cur = cur.right
    return res

N叉树遍历

时间复杂度:时间复杂度:O(M),其中 M 是 N 叉树中的节点个数。每个节点只会入栈和出栈各一次。

空间复杂度:O(M)。在最坏的情况下,这棵 N 叉树只有 2 层,所有第 2 层的节点都是根节点的孩子。

将根节点推出栈后,需要将这些节点都放入栈,共有 M−1个节点,因此栈的大小为 O(M)。

“”"

Definition for a Node.

class Node:
def init(self, val=None, children=None):
self.val = val
self.children = children
“”"

N叉树简洁递归

class Solution:
def preorder(self, root: ‘Node’) -> List[int]:
if not root: return []
res = [root.val]
for node in root.children:
res.extend(self.preorder(node))
return res

N叉树通用递归模板

class Solution:
def preorder(self, root: ‘Node’) -> List[int]:
res = []
def helper(root):
if not root:
return
res.append(root.val)
for child in root.children:
helper(child)
helper(root)
return res

N叉树迭代方法

class Solution:
def preorder(self, root: ‘Node’) -> List[int]:
if not root:
return []
s = [root]
# s.append(root)
res = []
while s:
node = s.pop()
res.append(node.val)
# for child in node.children[::-1]:
# s.append(child)
s.extend(node.children[::-1])
return res

作者:821218213
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/python3-er-cha-shu-suo-you-bian-li-mo-ban-ji-zhi-s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

**

另一种方法

**
其核心思想如下:

使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
如果遇到的节点为灰色,则将节点的值输出。
使用这种方法实现的中序遍历如下:

class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
WHITE, GRAY = 0, 1
res = []
stack = [(WHITE, root)]
while stack:
color, node = stack.pop()
if node is None: continue
if color == WHITE:
stack.append((WHITE, node.right))
stack.append((GRAY, node))
stack.append((WHITE, node.left))
else:
res.append(node.val)
return res

作者:hzhu212
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值