算法(2)-二叉树的遍历(递归/迭代)python实现

二叉树的遍历

  • 1.深度优先DFS
    • 1.1 DFS 递归解法
      • 1.1.1先序遍历
      • 1.1.2中序遍历
      • 1.1.3后序遍历
    • 1.2 DFS迭代解法
      • 1.2.1先序遍历
      • 1.2.2中序遍历
      • 1.2.3后序遍历
  • 2.广度优先BFS
  • 3.二叉树的最大深度
    • 3.1递归
    • 3.2迭代
  • 4.翻转二叉树
    • 4.1递归
    • 4.1迭代
  • 5.合并两棵二叉树
    • 5.1递归
    • 5.2迭代

有两种通用的遍历树的策略:深度优先遍历、广度优先遍历。
(树本身是一个递归的结构)

算法(2)-二叉树的遍历(递归/迭代)python实现_第1张图片
利用树类构造一个棵二叉树:

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
T=TreeNode(1)
n1=T.left=TreeNode(2)
n2=T.right=TreeNode(3)
n3=n1.left=TreeNode(4)
n4=n1.right=TreeNode(5)

1.深度优先DFS

DFS(Depth First Search)为二叉树的深度优先遍历方式,深度优先从根节点开始,往深处搜索至某个叶子节点,依据左孩子,右孩子,根节点的相对遍历顺序,可以分为先序遍历(根-左-右),中需遍历(左-根-右),后续遍历(左-右-根)。

1.1 DFS 递归解法

深度优先递归解法的三种顺序,框架一致。递归最重要的一点:递归结束条件,(1)当前节点为空,或者递归程序执行完最后一行。

1.1.1先序遍历

根-左-右 输出:[1,2,4,8,9,5,3,6,7]

class Solution(object):
    def PreOrder_rec(self,root):
        res=[]
        def DFS_pre(node,res):
            if node==None:           
                return
            res.append(node.val)     # 先中
            DFS_pre(node.left,res)   # 递归左子树
            DFS_pre(node.right,res)  # 递归右子树
        DFS_pre(root,res)
        return res

1.1.2中序遍历

左-根-右 输出:[8,4,9,2,5,1,6,3,7]

class Solution(object):
    def InOrder_rec(self, root):
        res=[]
        def DFS_In(node,res):
            if node==None:
                return
            DFS_In(node.left,res)
            res.append(node.val)
            DFS_In(node.right,res)
        DFS_In(root,res)
        return res

1.1.3后序遍历

左-右-根 输出[8,9,4,5,2,6,7,3,1]

class Solution(object):
    def BackOrder_rec(self, root):
        res=[]
        def DFS_Back(node,res):
            if node==None:
                return
            DFS_Back(node.left,res)
            DFS_Back(node.right,res)
            res.append(node.val)
        DFS_Back(root,res)
        return res

1.2 DFS迭代解法

二叉树深度优先迭代 要借助(先进后出)的特点。依据三种不同的顺序将不同的节点压入堆栈。

1.2.1先序遍历

根-左-右 输出:[1,2,4,8,9,5,3,6,7]。维护一个堆栈stack(python中可以用List 高效实现)
从根结点开始(curr=Root);
如果当前节点非空 访问当前结点的值,将当前节点的右子树节点推入堆栈,更新当前结点:curr=curr.left.;
如果当前节点为空:弹出堆栈保存的最后一个右子树结点。

class Solution(object):
    def PreOrder_iter(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        res=[]
        stack=[]
        curr=root
        while(curr or stack):
            if curr:
                res.append(curr.val)
                stack.append(curr.right)     # 递归到叶子结点时,会出现stack 增加None的情形
                curr=curr.left               # 将None pop 出来就是多了一次无增res操作
            else:
                curr=stack.pop()
        return res

1.2.2中序遍历

左-根-右 输出:[8,4,9,2,5,1,6,3,7]
维护一个堆栈stack(python中可以用List 高效实现)。
从根结点开始(curr=Root):
如果当前节点非空:将当前结点推入堆栈,更新当前结点:curr=curr.left;
如果当前节点为空:弹出堆栈保存的最后一个结点,访问该结点的值,更新当前结点:curr=curr.right.

class Solution(object):
    def InOrer_iter(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        res=[]
        stack=[]
        curr=root
        while(curr or stack):
            if curr:
                stack.append(curr)
                curr=curr.left      # 一直搜索左子树到叶子节点,将路径上的结点推入堆栈
            else:                   
                curr=stack.pop()
                res.append(curr.val)
                curr=curr.right    # 访问右子树结点
        return res

1.2.3后序遍历

左-右-根 输出[8,9,4,5,2,6,7,3,1]
维护一个堆栈stack(python中可以用List 高效实现)。
从根结点开始(curr=Root):
如果当前节点非空:将当前结点推入堆栈,更新当前结点:curr=curr.left;
如果当前节点为空:弹出堆栈保存的最后一个结点,访问该结点的值,更新当前结点:curr=curr.right.

class Solution(object):
    def BackOrder_iter(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        res=[]
        stack=[]
        curr=root
        while(curr or stack):  # 左右根尅分解为:根右左+逆序(根右左和根左右是一样的实现框架)
            if curr:
                res.append(curr.val)
                stack.append(curr.left)
                curr=curr.right
            else:
                curr=stack.pop()
        return res[::-1]

2.广度优先BFS

BFS(Breadth First Search)为二叉树的广度优先遍历方式,又叫层次遍历从根节点开始逐层遍历二叉树。1->2->3->4->5->6->7->8->9

借助队列 先进后出 的特点,将节点不断推入队列中。python 中用list可以快速实现队列。
迭代解法 输出[1,2,3,4,5,6,7,8,9]

class Solution(object):
    def BFS_iter1(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        levels=[]
        queue=[root]
        if  not root:
            return levels
        while(queue):      # 
            node=queue.pop(0)        
            levels.append(node.val)
            if node.left:            # 装进队列里的元素都是非空的。
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        return levels

leetcode 102 要求输出的结果每一层的元素放在一起,则需要维护一个list,用于放置每层的元素,levels=[[1],[2,3],[4,5,6,7],[8,9]],同时一个level变量用于指示当前节点位于的层数。

迭代解法 :输出[[1],[2,3],[4,5,6,7],[8,9]]

class Solution(object):
    def levelOrder_iter2(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        levels=[]
        queue=[root]
        if  not root:
            return levels
        while(queue):      # 处理每一层前,增加一次levels,装该层的节点值
            levels.append([])
            n_q=len(queue)  # 该层节点个数
            for i in range(n_q): # i:[0,n_q-1] # 逐个处理该层节点:首先弹出队列首,记录数值,有左右孩子的将孩子压入队列
                node=queue.pop(0)
                levels[-1].append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return levels

递归解法 输出[[1],[2,3],[4,5,6,7],[8,9]]
实际上是利用DFS实现的BFS,每当DFS遍历到一个新的节点,就把它加入到所在层的list里面去。

class Solution(object):
    def levelOrder_rec(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        levels=[]
        if  not root:
            return levels
        def BFS_rec(node,level):
            if len(levels)==level:        # level作为levels 的索引,应该
                levels.append([])
            levels[level].append(node.val)  # 将当前节点放入指定的层
            if node.left:					# 如果有左右孩子,递归调用BFS_rec
                BFS_rec(node.left,level+1) 
            if node.right:
                BFS_rec(node.right,level+1)
        BFS_rec(root,0)
        return levels

参考博文:
二叉树的前中后遍历,层次遍历,树的递归问题(递归与迭代python):https://www.cnblogs.com/liuyicai/p/10156455.html
二叉树及其遍历方法—python实现:https://www.cnblogs.com/lliuye/p/9143676.html

3.二叉树的最大深度

3.1递归

def Max_depth(node):
    if node==None:
        return 0
    dl=DFS(node.left)
    dr=DFS(node.right)
    res=max(dl,dr)+1
    return res
res=Max_depth(root)
return res

3.2迭代


def maxDepth(self, root):
    de=0
    if root:
        stack=[(1,root)]
    else:
        return 0
    while(stack):
        cur_de,node=stack.pop()
        if node:     # 只有当结点存在时+1后的深度才会被采用
            de=max(de,cur_de)
            stack.append((cur_de+1,node.left))
            stack.append((cur_de+1,node.right))
    return de

4.翻转二叉树

4.1递归

自低向上的交换过程

class Solution(object):
    def invertTree(self, root):
        if root==None:
            return
        self.invertTree(root.left)
        self.invertTree(root.right)
        root.left,root.right=root.right,root.left
        return root

4.1迭代

自顶向下的交换过程

class Solution(object):
    def invertTree(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        if root:
            q=[root]
        else:
            return root
        while(q):
            curr=q.pop(0)
            curr.left,curr.right=curr.right,curr.left
            if curr.left:
                q.append(curr.left)
            if curr.right:
                q.append(curr.right)

        return root

5.合并两棵二叉树

leetcode617: 两棵树有公共结点处的值为两数对应节点值想加

5.1递归

class Solution(object):
    def mergeTrees(self, t1, t2):
        if not t1 and not t2:
            return None
        root=TreeNode(0)
        if t1 and t2:
            root.val=t1.val+t2.val
            root.left=self.mergeTrees(t1.left,t2.left)
            root.right=self.mergeTrees(t1.right,t2.right)
        elif t1:
            root.val=t1.val
            root.left=self.mergeTrees(t1.left,None)
            root.right=self.mergeTrees(t1.right,None)
        else:
            root.val=t2.val
            root.left=self.mergeTrees(None,t2.left)
            root.right=self.mergeTrees(None,t2.right)
        return root
        class Solution(object):
    def mergeTrees2(self, t1, t2):
        if t1==None:
            return t2
        if t2==None:
            return t1
        t1.val+=t2.val
        t1.left=self.mergeTrees2(t1.left,t2.left)
        t1.right=self.mergeTrees2(t1.right,t2.right)
        return t1

5.2迭代

首先把两棵树的根节点入栈,栈中的每个元素都会存放两个根节点,并且栈顶的元素表示当前需要处理的节点。
以t1作为最后的输出返回,
当前结点的处理( 在stack里面的东西都是非空的):
两者相加的值放入t1.val
子结点的处理:
t1没有做孩子,t2的左孩子给t1.
t1,t2同时有左孩子,将其同时入栈,
右孩子的处理同理。

class Solution(object):
    def mergeTrees(self, t1, t2):
        if t1==None:
            return t2
        if t2==None:
            return t1
        stack=[(t1,t2)]
        while(stack):
            node1,node2=stack.pop() # 在stack里面的东西都是非零的
            node1.val+=node2.val
            if node1.left==None:
                node1.left=node2.left
            elif node1.left and node2.left:  # 1.left 和2.left同时非零
                stack.append([node1.left,node2.left])
            if node1.right==None:
                node1.right=node2.right      # 放过来之后就有。
            elif  node1.right and node2.right:  # 1.left 和2.left同时非零
                stack.append([node1.right,node2.right])
        return t1

你可能感兴趣的:(算法)