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]
posted @ 2019-10-29 18:01  catyuang  阅读(1261)  评论(0编辑  收藏  举报