二叉树的循环遍历方法

Author Avatar
zzz1220 6月 01, 2019
  • 在其它设备中阅读本文章
👉👉本文共1k字📘 读完共需4分钟⌚

最近稍微刷了一下leetcode,想巩固一下编程功底,但是发现工作后的很少用到在学校时用的数据结构,好多都忘了,在这里做下记录。

1.二叉树的前序,中序,后序遍历

前序遍历方向是 中 左 右

中序遍历方向是 左 中 右

后序遍历方向是 右 左 中

根据上面的定义,看的出来对于左右节点,顺序是不变的,只是中间节点出现的位置改变。所以,这也是一个防止忘记的技巧。

2.代码实现

# 定义节点对象
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

# 准备测试数据
a = TreeNode(1)
a.left = TreeNode(2)
a.left.left = TreeNode(4)
a.left.right = TreeNode(5)
a.right = TreeNode(3)
a.right.left = TreeNode(6)
a.right.right = TreeNode(7)

class Solution:
    def inorderTraversal(self,root):
        """
        递归实现中序遍历
        """
        if not root:
            return []
        return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right)
    
    def inerderTraversalLoop(self,root):
        """
        循环实现中序遍历
        """
        result = []
        stack = []
        curr = root
        while curr or stack:
            if curr:
                stack.append(curr)
                curr=curr.left
            else:
                curr = stack.pop()
                result.append(curr.val)
                curr = curr.right
        return result        
            
            
    
    def predorderTraversal(self, root):
        """
        递归实现前序遍历
        """
        if not root:
            return []
        return [root.val] + self.predorderTraversal(root.left) + self.predorderTraversal(root.right)
        
    def predorderTraversalLoop(self,root):
        """
        循环实现前序遍历
        """
        result = []
        stack = []
        curr = root
        while curr or stack:
            if curr:
                result.append(curr.val)
                stack.append(curr.right)
                curr = curr.left
            else:
                curr = stack.pop()
                
        return result         
            
    
    
    def postorderTraversal(self,root):
        """
        递归实现后续遍历
        """
        if not root:
            return []
        return self.postorderTraversal(root.left) + self.postorderTraversal(root.right) + [root.val]
    
    
    def postorderTraversalLoop(self,root):
        """
        循环实现后续遍历
        """
        result = []
        stack = []
        curr = root
        while curr or stack:
            if curr:
               result.append(curr.val)
               stack.append(curr.left)
               curr = curr.right
            else:
               curr = stack.pop()
        return result[::-1]     
        
    
if __name__ == "__main__":
    s = Solution()
    print(s.inorderTraversal(a))
    print(s.inerderTraversalLoop(a))
    print(s.predorderTraversal(a))
    print(s.predorderTraversalLoop(a))
    print(s.postorderTraversal(a))
    print(s.postorderTraversalLoop(a))
# [4, 2, 5, 1, 6, 3, 7]
# [4, 2, 5, 1, 6, 3, 7]
# [1, 2, 4, 5, 3, 6, 7]
# [1, 2, 4, 5, 3, 6, 7]
# [4, 5, 2, 6, 7, 3, 1]
# [4, 5, 2, 6, 7, 3, 1]   

上面就是实现代码。

先说下递归实现,根据第一节的遍历顺序定义,这里很简单就可以写出递归程序,只是返回的时候,更改下中间节点的位置就好。

在说下循环实现,在LeetCode里面,循环都是hardmiddle的题,可见,用循环实现起来并不容易。

主要是要在一个函数里面实现遍历到整个树形结构,如果你能想到用stack)来存节点,那么你应该差不多对数据结构运用有一定经验了。

如下的二叉树

      1
   2      3
4    5

对于中序遍历

每次将当前结点curr的左子结点push到栈中,直到当前结点curr为None。这时,pop出栈顶的第一个元素,设其为当前结点,并输出该结点的val值,且开始遍历该结点的右子树。当stackcurr都为空的时候,结束循环。

对于前序遍历

输出当前结点currval,并将右子结点push到栈中,然后将左子结点设为当前结点。入栈和出栈条件(当前结点curr不为None时,每一次循环将当前结点curr入栈;当前结点currNone时,则出栈一个结点)以及循环结束条件(整个循环在stackcurr皆为None的时候结束)与中序遍历一模一样。

对于后序遍历

后序遍历在leetcode上是hard难度的题,这里有个技巧,后序是左右中,我们按照中右左的方式遍历,然后反向输出就可以了。而且中右左不就是前序遍历左右互相换下吗?

总结

二叉树的循环遍历,还是要借助于栈这个非常有用的数据结构,有时我们都明白,比如,栈啊,队列啊,这些结构有什么特性,但是,要真正灵活的使用这些数据结构,还需要多多练习。