劍指Offer 04 - 重建二叉樹詳解(Python版)

題目描述:

輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

什麼是二叉樹?

二叉樹(Binary Tree)是n(n≥0)個節點的有限集合,它或者是空集(n=0),或者是由一個根節點以及兩棵互不相交的、分別稱爲左子樹和右子樹的二叉樹組成。二叉樹與普通有序樹不同,二叉樹嚴格區分左孩子和右孩子,即使只有一個子節點也要區分左右。

二叉樹的遍歷

遍歷 :沿某條搜索路徑周遊二叉樹,對樹中的每一個節點訪問一次且僅訪問一次。
遇到沒遍歷的新節點都當根處理

先序遍歷: 先訪問樹根,再訪問左子樹,最後訪問右子樹;根左右
中序遍歷: 先訪問左子樹,再訪問樹根,最後訪問右子樹;左根右
後序遍歷: 先訪問左子樹,再訪問右子樹,最後訪問樹根;左右根
層次遍歷: 從根節點開始,逐層從左向右進行遍歷。
在這裏插入圖片描述

使用Python實現二叉樹

# 二叉樹節點
class TreeNode:
  def __init__(self, val=None, left=None, right=None):
    self.val = val
    self.left = left
    self.right = right

#  二叉樹操作
class Bitree:
  def __init__(self, root=None):
    self.root = root  # 獲取樹根

  # 先序遍歷
  def preOrder(self,node):
    # 傳入根節點
    if node is None:
      return
	# 打印根節點數據
    print(node.val,end=' ')
    # 將根節點的左點節 作爲根節點 遞歸調用自身,直至滿足node is None,停止遞歸
    self.preOrder(node.left)
    self.preOrder(node.right)

  #  中序遍歷
  def inOrder(self, node):
    if node is None:
      return
    self.inOrder(node.left)
    print(node.val, end=' ')
    self.inOrder(node.right)

  #  後序遍歷
  def postOrder(self, node):
    if node is None:
      return
    self.postOrder(node.left)
    self.postOrder(node.right)
    print(node.val, end=' ')
    
if __name__ == "__main__":
  #  後序遍歷 BFGDIHECA
  # 構建樹 
  b = TreeNode('B')
  f = TreeNode('F')
  g = TreeNode('G')
  d = TreeNode('D', f, g)
  i = TreeNode('I')
  h = TreeNode('H')
  e = TreeNode('E', i, h)
  c = TreeNode('C', d, e)
  a = TreeNode('A', b, c)  # 樹根

  #  初始化樹對象,得到樹根
  bt = Bitree(a)
  # 先序
  bt.preOrder(bt.root)
  print()
  #  中序
  bt.inOrder(bt.root)
  print()
  #  後序
  bt.postOrder(bt.root)
  print()

根據題目構建二叉樹圖

在這裏插入圖片描述

構建代碼

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    # 返回構造的TreeNode根節點
    def reConstructBinaryTree(self, pre: list, tin: list) -> object:
        """
        pre: 前序列表
        tin: 中序列表
        """
        # write code here
        if len(pre) == 0:
            return None
        if len(pre) == 1:
            return TreeNode(pre[0])
        else:
            root = TreeNode(pre[0])  # 前序序列的第一個肯定是當前子樹的根節點
            rootid = tin.index(root.val)  # 通過根節點在中序序列中的位置劃分出左右子樹包含的節點
            root.left = self.reConstructBinaryTree(pre[1:rootid + 1], tin[:rootid])
            root.right = self.reConstructBinaryTree(pre[rootid + 1:], tin[rootid + 1:])
        return root

代碼流程

在這裏插入圖片描述

對結果進行驗證

完整代碼

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    # 返回構造的TreeNode根節點
    def reConstructBinaryTree(self, pre: list, tin: list) -> object:
        """
        pre: 前序列表
        tin: 中序列表
        """
        # write code here
        if len(pre) == 0:
            return None
        if len(pre) == 1:
            return TreeNode(pre[0])
        else:
            root = TreeNode(pre[0])  # 前序序列的第一個肯定是當前子樹的根節點
            rootid = tin.index(root.val)  # 通過根節點在中序序列中的位置劃分出左右子樹包含的節點
            root.left = self.reConstructBinaryTree(pre[1:rootid + 1], tin[:rootid])
            root.right = self.reConstructBinaryTree(pre[rootid + 1:], tin[rootid + 1:])
        return root

class Bitree:
    def __init__(self, root=None):
        self.root = root  # 獲取樹根

    #  先序遍歷
    def preOrder(self, node):
        # 傳入根節點
        if node is None:
            return
        # 打印根節點數據
        print(node.val, end=' ')
        # 將根節點的做點節 作爲根節點 調用自身
        self.preOrder(node.left)
        self.preOrder(node.right)

    #  中序遍歷
    def inOrder(self, node):
        if node is None:
            return
        self.inOrder(node.left)
        print(node.val, end=' ')
        self.inOrder(node.right)

    #  後序遍歷
    def postOrder(self, node):
        if node is None:
            return
        self.postOrder(node.left)
        self.postOrder(node.right)
        print(node.val, end=' ')

if __name__ == '__main__':
    s = Solution()
    pre = [1, 2, 4, 7, 3, 5, 6, 8]
    tin = [4, 7, 2, 1, 5, 3, 8, 6]

    root = s.reConstructBinaryTree(pre, tin)

    #  初始化樹對象,得到樹根
    bt = Bitree(root)
    #  先序
    bt.preOrder(bt.root) # 1 2 4 7 3 5 6 8 
    print()
    #  中序
    bt.inOrder(bt.root) # 4 7 2 1 5 3 8 6 
    print()
    #   後序
    bt.postOrder(bt.root) # 7 4 2 5 8 6 3 1 
    print()

補充 代碼實現二叉樹層次遍歷

'''
利用隊列先進先出特性,實現二叉樹層次遍歷
'''
#  自定義隊列異常
class QueueError(Exception):
  pass

# 隊列操作類
class SQueue:
  def __init__(self):
    self._elems = []

  # 判斷隊列空
  def is_empty(self):
    return self._elems == []

  # 入隊 從列表尾部
  def enqueue(self, elem):
    self._elems.append(elem)

  # 出隊 從列表開頭
  def dequeue(self):
    if not self._elems:
      raise QueueError("Queue is empty")
    return self._elems.pop(0)

# 二叉樹節點
class TreeNode:
  def __init__(self, val=None, left=None, right=None):
    self.val = val
    self.left = left
    self.right = right
    
class Bitree:
    def __init__(self, root=None):
        self.root = root  # 獲取樹根
        
  	# 層次遍歷
  	def levelOrder(self,node):
    	sq = SQueue()
    	sq.enqueue(node) # 從node遍歷
    	while not sq.is_empty():
      	node = sq.dequeue() # 出隊一個
      	print(node.val,end=' ') # 遍歷數據
      	if node.left:
        	sq.enqueue(node.left)
      	if node.right:
        	sq.enqueue(node.right)

如有錯誤,歡迎指正

發佈了15 篇原創文章 · 獲贊 17 · 訪問量 1263
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章