07 樹形結構及其算法


  1. 滿二叉樹(full binary tree)
    如果二叉樹的高度為 h,樹的節點數為 2^h-1,h≥0,就稱此樹為滿二叉樹。
  2. 完全二叉樹(complete binary tree)
    如果二叉樹的高度為 h,樹的節點數小於 2^h-1,編號從上到下、從左到右一一對應(如果只有一個子樹,必須是左子樹。不能只有右子樹,沒有左子樹)。如果有N個節點,那么此二叉樹的層數 h 為⌊log(N+1)⌋。
  3. 斜二叉樹(skewed binary tree)
    完全沒有右節點,左斜二叉樹。
    完全沒有做節點,右斜二叉樹。
  4. 嚴格二叉樹(strictly binary tree)
    二叉樹中每一個非終端節點均有非空的左右子樹。

用數組實現二叉樹

使用有序的一維數組表示二叉樹,首先可將此二叉樹想成滿二叉樹,且第k層具有2^(k-1)個節點,按序放在一維數組中。

  1. 左子樹索引值是父節點索引值*2
  2. 右子樹索引值是父節點索引值*2+1
  • 二叉查找樹的特點
    可以是空集合,若不是空集合,則節點上一定要有一個鍵值。
    每一個樹根的值需大於左子樹的值。
    每一個樹根的值需小於右子樹的值。
    左右子樹也是二叉查找樹。
    樹的每個節點值都不相同。
  """
  按序輸入一顆二叉樹節點的數據,分別是0,6,3,5,4,7,8,9,2,
  並建立一顆查找樹,最后輸出存儲此二叉樹的一維數組。
  """
  def btree_create(btree, data, length):
      for i in range(1, length):
          level = 1
          while btree[level] != 0:  # 0不參與爭斗,用來補位
              if data[i] > btree[level]:  # 如果原始數組內的值大於樹根,則往右子樹比較
                  level = level * 2 + 1
              else:  # 小於等於樹根,則往左子樹比較
                  level = level * 2
          btree[level] = data[i]  # 把數組值放進二叉樹
  
  
  length = 9
  data = [0, 6, 3, 5, 4, 7, 8, 9, 2]
  btree = [0] * 16
  print("原始數組內容為:")
  for i in range(length):
      print("[%2d] " % data[i], end='')
  print('')
  btree_create(btree, data, length)
  print("二叉樹內容為:")
  for i in range(1, 16):
      print("[%2d] " % btree[i], end='')
  print()

用鏈表實現二叉樹

對於節點的添加與刪除容易,但是難找到父節點,除非在每一個節點增加一個父字段

  • 二叉樹類聲明
  class Tree:
      def __init__(self):
          self.data = 0
          self.left = None
          self.right = None
  • 以鏈表建立二叉樹:
  def create_tree(root, val):
      newnode = Tree()
      newnode.data = val
      newnode.left = None
      newnode.right = None
      if root == None:
          root = newnode
          return root
      else:
          current = root  # 父節點
          # 判斷左右子樹走向
          while current != None:
              backup = current
              if current.data > val:
                  current = current.left
              else:
                  current = current.right
          # 把尾節點值和新增節點值比較,把節點放進鏈表
          if backup.data > val:
              backup.left = newnode
          else:
              backup.right = newnode
          return root
  
  data = [5, 6, 24, 8, 12, 3, 17, 1, 9]
  ptr = None
  root = None
  for i in range(9):
      ptr = create_tree(ptr, data[i])
  print("樹根左邊:")
  root = ptr.left
  while root != None:
      print("%d" % root.data)
      root = root.left or root.right
  print('-----')
  print("樹根右邊:")
  root = ptr.right
  while root != None:
      print("%d" % root.data)
      root = root.right or root.left
  print()
  左邊:
  3
  1
  -----
  右邊:
  6
  24
  8
  12
  17

二叉樹遍歷

  • 中序遍歷(Inorder):左子樹-樹根-右子樹
  def inorder(ptr):
      if ptr != None:
          inorder(ptr.left)
          print("[%2d] " % ptr.data, end='')
          inorder(ptr.right)

前序遍歷(Preorder):樹根-左子樹-右子樹

  def preorder(ptr):
      if ptr != None:
          print("[%2d] " % ptr.data, end='')
          preorder(ptr.left)
          preorder(ptr.right)

后序遍歷(Postorder):左子樹-右子樹-樹根

  def postorder(ptr):
      if ptr != None:
          postorder(ptr.left)
          postorder(ptr.right)
          print("[2d] " % ptr.data, end='')

二叉樹節點的查找

二叉樹在建立時,是根據左子樹 < 樹根 < 右子樹的原則建立的,因此只需從樹根出發比較鍵值,如果比樹根大就往右,否則往左而下。

  def search(ptr, val):
      while True:
          if ptr == None:
              return None
          if ptr.data == val:
              return ptr
          elif ptr.data > val:
              ptr = ptr.left
          else:
              ptr = ptr.right

二叉樹節點的插入

  if search(ptr, data) != None:
      print("二叉樹中有此節點了")
  else:
      ptr = create_tree(ptr, data)
      inorder(ptr)

二叉樹節點的刪除

刪除的節點為樹葉,只要將其相連的父節點指向 None 即可
刪除的節點只有一棵子樹
刪除的節點有兩棵子樹

  • 中序立即先行者(inorder immediate predecessor):將欲刪除節點的左子樹中最大者向上提。簡單來說,就是在該節點的左子樹,往右尋找,知道右指針為None,這個節點就是中序立即先行者。
  • 中序立即后繼者(inorder immediate successor):把要刪除節點的右子樹中最小者向上提。簡單來說,就是在該節點的右子樹,往左尋找,知道左指針為None,這個節點就是中序立即后繼者。

堆積樹(heap tree)排序算法

選擇排序的改進,可以減少在選擇排序算法中的比較次數。堆積樹是一種特殊的二叉樹,可分為最大堆積樹和最小堆積樹。

  • 最大堆積樹滿足:
    它是一個完全二叉樹。
    所有節點的值都大於或等於它左右子節點的值。
    樹根是堆積樹中最大的。
  • 最小堆積樹滿足:
    它是一個完全二叉樹。
    所有節點的值都小於或等於它左右子節點的值。
    樹根是堆積樹中最小的。
  def heap(data, size):
      for i in range(int(size / 2), 0, -1):  # 建立堆積樹節點
          ad_heap(data, i, size - 1)
      print("\n堆積的內容:", end='')
      for i in range(1, size):
          print("[%2d ]" % data[i], end='')
      print("\n")
      for i in range(size - 2, 0, -1):  # 堆積排序
          data[i + 1], data[1] = data[1], data[i + 1]  # 頭尾節點交換
          ad_heap(data, 1, i)  # 處理剩余節點
          print("處理過程:", end='')
          for j in range(1, size):
              print("[%2d ]" % data[j], end='')
          print()
  
  
  def ad_heap(data, i, size):
      j = 2 * i
      tmp = data[i]
      post = 0
      while j <= size and post == 0:
          if j < size:
              if data[j] < data[j + 1]:  # 找出最大節點
                  j += 1
          if tmp >= data[j]:  # 若樹根較大,則繼續比較
              post = 1
          else:  # 若樹根較小,則繼續比較
              data[int(j / 2)] = data[j]
              j = 2 * j
      data[int(j / 2)] = tmp  # 指定樹根為父節點

  def main():
      data = [0, 5,6,4,8,3,2,7,1]
      size = len(data)
      print('原始數組為:', end='')
      for i in range(1, size):
          print('[%2d]' % data[i], end='')
      heap(data, size)
      print('排序結果為:')
      for i in range(1, size):
          print('[%2d]' % data[i], end='')

  main()
  原始數組為:[ 5][ 6][ 4][ 8][ 3][ 2][ 7][ 1]
  堆積的內容:[ 8 ][ 6 ][ 7 ][ 5 ][ 3 ][ 2 ][ 4 ][ 1 ]
  
  處理過程:[ 7 ][ 6 ][ 4 ][ 5 ][ 3 ][ 2 ][ 1 ][ 8 ]
  處理過程:[ 6 ][ 5 ][ 4 ][ 1 ][ 3 ][ 2 ][ 7 ][ 8 ]
  處理過程:[ 5 ][ 3 ][ 4 ][ 1 ][ 2 ][ 6 ][ 7 ][ 8 ]
  處理過程:[ 4 ][ 3 ][ 2 ][ 1 ][ 5 ][ 6 ][ 7 ][ 8 ]
  處理過程:[ 3 ][ 1 ][ 2 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ]
  處理過程:[ 2 ][ 1 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ]
  處理過程:[ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ]
  排序結果為:
  [ 1][ 2][ 3][ 4][ 5][ 6][ 7][ 8]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM