Python 实现二叉查找树的示例代码


Posted in Python onDecember 21, 2020

二叉查找树

  • 所有 key 小于 V 的都被存储在 V 的左子树
  • 所有 key 大于 V 的都存储在 V 的右子树

BST 的节点

class BSTNode(object):
  def __init__(self, key, value, left=None, right=None):
    self.key, self.value, self.left, self.right = key, value, left, right

二叉树查找

如何查找一个指定的节点呢,根据定义我们知道每个内部节点左子树的 key 都比它小,右子树的 key 都比它大,所以 对于带查找的节点 search_key,从根节点开始,如果 search_key 大于当前 key,就去右子树查找,否则去左子树查找

NODE_LIST = [
  {'key': 60, 'left': 12, 'right': 90, 'is_root': True},
  {'key': 12, 'left': 4, 'right': 41, 'is_root': False},
  {'key': 4, 'left': 1, 'right': None, 'is_root': False},
  {'key': 1, 'left': None, 'right': None, 'is_root': False},
  {'key': 41, 'left': 29, 'right': None, 'is_root': False},
  {'key': 29, 'left': 23, 'right': 37, 'is_root': False},
  {'key': 23, 'left': None, 'right': None, 'is_root': False},
  {'key': 37, 'left': None, 'right': None, 'is_root': False},
  {'key': 90, 'left': 71, 'right': 100, 'is_root': False},
  {'key': 71, 'left': None, 'right': 84, 'is_root': False},
  {'key': 100, 'left': None, 'right': None, 'is_root': False},
  {'key': 84, 'left': None, 'right': None, 'is_root': False},
]


class BSTNode(object):
  def __init__(self, key, value, left=None, right=None):
    self.key, self.value, self.left, self.right = key, value, left, right


class BST(object):
  def __init__(self, root=None):
    self.root = root

  @classmethod
  def build_from(cls, node_list):
    cls.size = 0
    key_to_node_dict = {}
    for node_dict in node_list:
      key = node_dict['key']
      key_to_node_dict[key] = BSTNode(key, value=key)  # 这里值和key一样的

    for node_dict in node_list:
      key = node_dict['key']
      node = key_to_node_dict[key]
      if node_dict['is_root']:
        root = node
      node.left = key_to_node_dict.get(node_dict['left'])
      node.right = key_to_node_dict.get(node_dict['right'])
      cls.size += 1
    return cls(root)

  def _bst_search(self, subtree, key):
    """
    subtree.key小于key则去右子树找 因为 左子树<subtree.key<右子树
    subtree.key大于key则去左子树找 因为 左子树<subtree.key<右子树
    :param subtree:
    :param key:
    :return:
    """
    if subtree is None:
      return None
    elif subtree.key < key:
      self._bst_search(subtree.right, key)
    elif subtree.key > key:
      self._bst_search(subtree.left, key)
    else:
      return subtree

  def get(self, key, default=None):
    """
    查找树
    :param key:
    :param default:
    :return:
    """
    node = self._bst_search(self.root, key)
    if node is None:
      return default
    else:
      return node.value

  def _bst_min_node(self, subtree):
    """
    查找最小值的树
    :param subtree:
    :return:
    """
    if subtree is None:
      return None
    elif subtree.left is None:
      # 找到左子树的头
      return subtree
    else:
      return self._bst_min_node(subtree.left)

  def bst_min(self):
    """
    获取最小树的value
    :return:
    """
    node = self._bst_min_node(self.root)
    if node is None:
      return None
    else:
      return node.value

  def _bst_max_node(self, subtree):
    """
    查找最大值的树
    :param subtree:
    :return:
    """
    if subtree is None:
      return None
    elif subtree.right is None:
      # 找到右子树的头
      return subtree
    else:
      return self._bst_min_node(subtree.right)

  def bst_max(self):
    """
    获取最大树的value
    :return:
    """
    node = self._bst_max_node(self.root)
    if node is None:
      return None
    else:
      return node.value

  def _bst_insert(self, subtree, key, value):
    """
    二叉查找树插入
    :param subtree:
    :param key:
    :param value:
    :return:
    """
    # 插入的节点一定是根节点,包括 root 为空的情况
    if subtree is None:
      subtree = BSTNode(key, value)
    elif subtree.key > key:
      subtree.left = self._bst_insert(subtree.left, key, value)
    elif subtree.key < key:
      subtree.right = self._bst_insert(subtree.right, key, value)
    return subtree

  def add(self, key, value):
    # 先去查一下看节点是否已存在
    node = self._bst_search(self.root, key)
    if node is not None:
      # 更新已经存在的 key
      node.value = value
      return False
    else:
      self.root = self._bst_insert(self.root, key, value)
      self.size += 1

  def _bst_remove(self, subtree, key):
    """
    删除并返回根节点
    :param subtree:
    :param key:
    :return:
    """
    if subtree is None:
      return None
    elif subtree.key > key:
      subtree.right = self._bst_remove(subtree.right, key)
      return subtree
    elif subtree.key < key:
      subtree.left = self._bst_remove(subtree.left, key)
      return subtree
    else:
      # 找到了需要删除的节点
      # 要删除的节点是叶节点 返回 None 把其父亲指向它的指针置为 None
      if subtree.left is None and subtree.right is None:
        return None
      # 要删除的节点有一个孩子
      elif subtree.left is None or subtree.right is None:
        # 返回它的孩子并让它的父亲指过去
        if subtree.left is not None:
          return subtree.left
        else:
          return subtree.right
      else:
        # 有两个孩子,寻找后继节点替换,并从待删节点的右子树中删除后继节点
        # 后继节点是待删除节点的右孩子之后的最小节点
        # 中(根)序得到的是一个排列好的列表 后继节点在待删除节点的后边
        successor_node = self._bst_min_node(subtree.right)
        # 用后继节点替换待删除节点即可保持二叉查找树的特性 左<根<右
        subtree.key, subtree.value = successor_node.key, successor_node.value
        # 从待删除节点的右子树中删除后继节点,并更新其删除后继节点后的右子树
        subtree.right = self._bst_remove(subtree.right, successor_node.key)
        return subtree

  def remove(self, key):
    assert key in self
    self.size -= 1
    return self._bst_remove(self.root, key)

以上就是Python 实现二叉查找树的示例代码的详细内容,更多关于Python 实现二叉查找树的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
使用Python的Scrapy框架编写web爬虫的简单示例
Apr 17 Python
python使用 HTMLTestRunner.py生成测试报告
Oct 20 Python
Python多进程库multiprocessing中进程池Pool类的使用详解
Nov 24 Python
Django如何配置mysql数据库
May 04 Python
Sanic框架路由用法实例分析
Jul 16 Python
python将print输出的信息保留到日志文件中
Sep 27 Python
Python编写一个验证码图片数据标注GUI程序附源码
Dec 09 Python
pytorch实现对输入超过三通道的数据进行训练
Jan 15 Python
Python3.7实现验证码登录方式代码实例
Feb 14 Python
解决pycharm每次打开项目都需要配置解释器和安装库问题
Feb 26 Python
python利用蒙版抠图(使用PIL.Image和cv2)输出透明背景图
Aug 04 Python
python openpyxl模块的使用详解
Feb 25 Python
如何利用Python matplotlib绘制雷达图
Dec 21 #Python
OpenCV+python实现膨胀和腐蚀的示例
Dec 21 #Python
python opencv肤色检测的实现示例
Dec 21 #Python
OpenCV+Python3.5 简易手势识别的实现
Dec 21 #Python
如何使用python-opencv批量生成带噪点噪线的数字验证码
Dec 21 #Python
python 录制系统声音的示例
Dec 21 #Python
用python发送微信消息
Dec 21 #Python
You might like
深入了解php4(1)--回到未来
2006/10/09 PHP
用PHP生成静态HTML速度快类库
2007/03/18 PHP
apache+codeigniter 通过.htcaccess做动态二级域名解析
2012/07/01 PHP
本地机apache配置基于域名的虚拟主机详解
2013/08/10 PHP
SUN的《AJAX与J2EE》全文译了
2007/02/23 Javascript
jquery关于图形报表的运用实现代码
2011/01/06 Javascript
Javascript中设置默认参数值示例
2014/09/11 Javascript
jQuery实现的Tab滑动选项卡及图片切换(多种效果)小结
2015/09/14 Javascript
倾力总结40条常见的移动端Web页面问题解决方案
2016/05/24 Javascript
非常实用的js验证框架实现源码 附原理方法
2016/06/08 Javascript
jQuery纵向导航菜单效果实现方法
2016/12/19 Javascript
Angular如何在应用初始化时运行代码详解
2018/06/11 Javascript
原生JavaScript实现remove()和recover()功能示例
2018/07/24 Javascript
JS跨域请求的问题解析
2018/12/03 Javascript
浅谈express.js框架中间件(middleware)
2019/04/07 Javascript
使用Vue CLI创建typescript项目的方法
2019/08/09 Javascript
原生javascript制作贪吃蛇小游戏的方法分析
2020/02/26 Javascript
在Python的Flask框架中使用日期和时间的教程
2015/04/21 Python
python 迭代器和iter()函数详解及实例
2017/03/21 Python
python3模块smtplib实现发送邮件功能
2018/05/22 Python
python判断设备是否联网的方法
2018/06/29 Python
详解Python做一个名片管理系统
2019/03/14 Python
Python PIL读取的图像发生自动旋转的实现方法
2019/07/05 Python
Python 仅获取响应头, 不获取实体的实例
2019/08/21 Python
使用openCV去除文字中乱入的线条实例
2020/06/02 Python
PyCharm 2020.2 安装详细教程
2020/09/25 Python
python操作链表的示例代码
2020/09/27 Python
python Selenium 库的使用技巧
2020/10/16 Python
澳大利亚领先的在线药房:Pharmacy Online(有中文站)
2020/02/22 全球购物
函授毕业个人自我评价
2014/02/20 职场文书
2014年项目工作总结
2014/11/24 职场文书
2014年房地产个人工作总结
2014/12/20 职场文书
大学生毕业评语
2014/12/31 职场文书
个人年终总结怎么写
2015/03/09 职场文书
2015年度优秀员工获奖感言
2015/07/31 职场文书
国际最新研究在陨石中发现DNA主要成分 或由陨石带来地球
2022/04/29 数码科技