树的遍历总结 DFS+BFS+n叉树的遍历

关于树的遍历,前序,中序,后序,各有3种方法。
递归;迭代;莫里斯
这里进行总结:
①递归总结
递归只需注意一点,函数调用是小括号不是中括号,preorder(root)√ preorder[root]×

前序
class Solution:
    def preorderTraversal(self,root):
    	def preorder(node):
    		return [node.val]+preorder(node.left)+preorder(node.right) if node else []
    	return preorder[root] #递归只需注意一点,函数调用是小括号不是中括号,preorder(root)√  preorder[root]×

中序
class Solution:
    def inorderTraversal(self,root):
        def inorder(node):
        	return inorder(node.left)+[node.val] + inorder(node.right) if node else []
        return inorder(root)
后序
class Solution:
    def postorderTraversal(self,root):
        def postorder(node):
            return postorder(node.left)+postorder(node.right)+[node.val] if node else []
        return postorder(root)
        
时间复杂度O(n)
空间复杂度(h),h是树的高度

②迭代总结
while stack or root:#这个初始条件的意思应该是指,stack只要不为空,就继续遍历;加个or root主要是为了初始化,因为刚开始stack=[],而root不为空;改成stcak=[root],or root就可以去掉了;并不行,如果root也为空[],那么stack=[[]]是不为空的,但pop出去的tmp为空,其right是不存在的;所以初始都要判断一下stack和root是否为空;
所以初始化条件就是while stack or root:请记住

前序
class Solution:
    def preorderTraversal(self,root):
        res =[]
        stack =[]
        while stack or root:#请记住
            while root:
                res.append(root.val)#前序在遍历左节点之前,先将值加入结果       #直接根据中序迭代的方法,将记录遍历元素的时机改为了在入栈的时候就记录,也就是将父节点计入数组的时间提前了。
                stack.append(root)
                root = root.left
            tmp = stack.pop()
            root = tmp.right
        return res
中序        
class Solution:
    def inorderTraversal(self,root):
        res =[]
        stack =[]
        while stack or root:#请记住
            while root:
                stack.append(root)#不断添加左节点
                root = root.left#先不断遍历左节点
            tmp = stack.pop()
            res.append(tmp.val)#在左节点遍历结束,要不断遍历右节点的时候,将值加入结果
            root = tmp.right
        return res
后序,在前序遍历的基础上,先将right的顺序提前,left的顺序滞后,然后再反转res
class Solution:
    def postorderTraversal(self,root):
        res =[]
        stack = []
        while stack or root:
            while root:
                res.append(root.val)#前序遍历的标配
                stack.append(root)
                root = root.right#注意这里与前序的不同,将right的顺序提前
            tmp = stack.pop()
            root = tmp.left#将left的顺序滞后
        return res[::-1]
时间复杂度O(n)
空间复杂度(h),h是树的高度

③莫里斯遍历总结
当前节点有左子节点,就让左子节点的最右节点与当前节点建立联系

前序和中序的区别在于:
当左子节点存在的时候,添加节点元素的位置从拆除多余连接的时候变成了建立连接的时候,也就是在移动cur指针之前就得记录节点,保证当前指向的节点是最先记录的,左右子树的节点要靠后,并且不能重复记录元素。

后序和前序的区别在于:
和迭代时一样,将right提前,left滞后,再反转res;即right都替换为left,left都替换为right

前序
class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        node, output = root, []
        while node:  
            if not node.left: 
                output.append(node.val)
                node = node.right 
            else: 
                predecessor = node.left 

                while predecessor.right and predecessor.right is not node: 
                    predecessor = predecessor.right 

                if not predecessor.right:#建立连接,找到了最右节点
                    output.append(node.val)#前序莫里斯遍历与中序的区别就在于这里
                    predecessor.right = node  #建立右关系,与初始节点
                    node = node.left  #初始节点建立关系后,继续其左节点作为初始节点
                else:#拆除多余连接
                    predecessor.right = None
                    node = node.right         
        return output
中序
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        node, output = root, []
        while node:  
            if not node.left: #当前节点没有左子节点
                output.append(node.val)
                node = node.right 
            else: #当前节点有左子节点
                predecessor = node.left 
                while predecessor.right and predecessor.right is not node: 
                    predecessor = predecessor.right 
                if not predecessor.right:#建立联系,找到了最右节点
                    predecessor.right = node  #建立右关系,与初始节点
                    node = node.left  #初始节点建立关系后,继续其左节点作为初始节点
                else:#拆除联系
                    output.append(node.val)
                    predecessor.right = None
                    node = node.right         
        return output
后序
class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        node, output = root, []
        while node:  
            if not node.right: #①前序是判断左子节点,后序是判断右子节点
                output.append(node.val)
                node = node.left 
            else: 
                predecessor = node.right #②前序是从当前节点的左子节点不断找最右;后序是从当前节点的右子节点不断找最左
                while predecessor.left and predecessor.left is not node: 
                    predecessor = predecessor.left 

                if not predecessor.left:#建立连接,找到了最左节点
                    output.append(node.val)
                    predecessor.left = node  
                    node = node.right#③前序是建立初始节点node的关系后,继续其左节点作为初始节点;后序是继续其右节点作为初始节点
                else:#拆除多余连接
                    predecessor.left = None
                    node = node.left         
        return output[::-1]
时间复杂度O(n)空间复杂度O(1)

参考链接
https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/er-cha-shu-de-zhong-xu-bian-li-by-leetcode/

https://www.cnblogs.com/sunshuyi/p/12680577.html

https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/python3-er-cha-shu-suo-you-bian-li-mo-ban-ji-zhi-s/

https://leetcode-cn.com/problems/binary-tree-postorder-traversal/solution/mo-fang-di-gui-zhi-bian-yi-xing-by-sonp/ (评论python版本)

关于树的层次遍历,也做个总结:
递归和迭代2种方法,其中迭代用队列实现BFS;
2道题,正序遍历 和 逆序遍历;其实逆序遍历完全可以通过正序遍历 [::-1]实现
衍生:如果想让每一层逆序,则left和right换换位置即可,先加入right,再加入left
①递归

正序
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        levels = [] #存放结果的列表
        if not root:#定义边界条件
            return levels
        def helper(node,level):
            if len(levels)==level:#这个地方就很巧妙,只有有下一层的时候,才初始化[]
                levels.append([])
            levels[level].append(node.val)#将该层的值加入,然后去看该值的左,然后去看该值的右
            if node.left:
                helper(node.left,level+1)
            if node.right:
                helper(node.right,level+1)
        helper(root,0)
        return levels
逆序
即先返回最后一层,可以不改变原始的步骤,只需要加入levels的时候换下索引位置就可以了
class Solution:
    def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
        levels = []
        if not root:
            return levels
        def helper(node,level):
            if len(levels)==level:
                levels.insert(0,[])#每次初始化的放在前面;正序是不用管,后面append即可
            levels[-(level+1)].append(node.val)#-(level+1)表示该层的索引位置
            if node.left:
                helper(node.left,level+1)
            if node.right:
                helper(node.right,level+1)
        helper(root,0)
        return levels

②迭代BFS

正序
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        levels = []
        if not root:
            return levels
        level = 0
        queue = deque([root])
        while queue:
            levels.append([])
            for i in range(len(queue)):
                node = queue.popleft()
                levels[level].append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            level +=1
        return levels
逆序
class Solution:
    def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
        levels = []
        if not root:
            return levels
        level = 0
        queue = deque([root])
        while queue:
            levels.insert(0,[])#和递归一样,改这个
            for i in range(len(queue)):
                node = queue.popleft()
                levels[-(level+1)].append(node.val)#和递归一样,改这个
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            level +=1
        return levels

n叉树的遍历

递归
class Solution:
    def preorder(self, root: 'Node') -> List[int]:
        res = []
        def helper(node):
            if not node:
                return []
            res.append(node.val)
            for child in node.children:#2叉树是递归左右子结点,n叉树是循环递归子孩子节点
                helper(child)
        helper(root)
        return res
迭代
class Solution:
    def preorder(self, root: 'Node') -> List[int]:
        if not root:
            return []
        s = [root]
        res = []
        while s:
            node = s.pop()
            res.append(node.val)
            s.extend(node.children[::-1]) #全部遍历是用中括号[],用()要让评委笑了
            #node的所有子节点逆序推入栈中。例如子节点从左到右为 v1, v2, v3,那么推入栈的顺序应当为v3, v2, v1,这样就保证了下一个遍历到的节点(即node的第一个子节点 v1)出现在栈顶的位置
        return res

所有树的遍历的时间复杂度O(n),空间复杂度O(n),除了莫里斯是空间复杂度O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值