zoukankan      html  css  js  c++  java
  • 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("
    堆积的内容:", end='')
          for i in range(1, size):
              print("[%2d ]" % data[i], end='')
          print("
    ")
          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]
    
  • 相关阅读:
    top、ps -ef、ps aux的区别及内容详解
    img2pdf 报 img2pdf.AlphaChannelError: Refusing to work on images with alpha channel 的解决方案
    Scrapy命令行调用传入自定义参数
    查询Linux CPU架构
    LeetCode 216. 组合总和 III | Python
    LeetCode 40. 组合总和 II | Python
    LeetCode 39. 组合总和 | Python
    LeetCode 77. 组合 | Python
    LeetCode 347. 前 K 个高频元素 | Python
    LeetCode 107. 二叉树的层次遍历 II | Python
  • 原文地址:https://www.cnblogs.com/catyuang/p/11760502.html
Copyright © 2011-2022 走看看