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学习笔记(一)(基础入门之环境搭建)
Jun 05 Python
python简单实现获取当前时间
Aug 27 Python
Python编程之Re模块下的函数介绍
Oct 28 Python
python图像常规操作
Nov 11 Python
python交互式图形编程实例(三)
Nov 17 Python
Django中url的反向查询的方法
Mar 14 Python
python实现俄罗斯方块
Jun 26 Python
python 读取文本文件的行数据,文件.splitlines()的方法
Jul 12 Python
python读取图片的方式,以及将图片以三维数组的形式输出方法
Jul 03 Python
python从zip中删除指定后缀文件(推荐)
Dec 05 Python
python raise的基本使用
Sep 10 Python
Python访问Redis的详细操作
Jun 26 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
PHP与Java进行通信的实现方法
2013/10/21 PHP
javascript多种数据类型表格排序代码分析
2010/09/11 Javascript
ASP.NET jQuery 实例6 (实现CheckBoxList成员全选或全取消)
2012/01/13 Javascript
javascript 树形导航菜单实例代码
2013/08/13 Javascript
Javascript学习笔记之 函数篇(三) : 闭包和引用
2014/11/23 Javascript
javascript函数声明和函数表达式区别分析
2014/12/02 Javascript
js选项卡的制作方法
2017/01/23 Javascript
jQuery中map函数的两种方式
2017/04/07 jQuery
原生js实现可兼容PC和移动端的拖动滑块功能详解【测试可用】
2019/08/15 Javascript
解决使用layui的时候form表单中的select等不能渲染的问题
2019/09/18 Javascript
使用node.JS中的url模块解析URL信息
2020/02/06 Javascript
[59:15]EG vs LGD 2018国际邀请赛淘汰赛BO3 第一场 8.26
2018/08/29 DOTA
wtfPython—Python中一组有趣微妙的代码【收藏】
2018/08/31 Python
python生成每日报表数据(Excel)并邮件发送的实例
2019/02/03 Python
PyQt5 多窗口连接实例
2019/06/19 Python
详解Matplotlib绘图之属性设置
2019/08/23 Python
python实现WebSocket服务端过程解析
2019/10/18 Python
Python通过Manager方式实现多个无关联进程共享数据的实现
2019/11/07 Python
解决Python paramiko 模块远程执行ssh 命令 nohup 不生效的问题
2020/07/14 Python
台湾最大网路书店:博客来
2018/03/18 全球购物
生日礼品店创业计划书范文
2014/03/21 职场文书
弘扬民族精神演讲稿
2014/05/07 职场文书
市级优秀班主任事迹材料
2014/05/13 职场文书
班子成员四风问题自我剖析材料
2014/09/29 职场文书
2014年行政助理工作总结
2014/11/19 职场文书
2014年初级职称工作总结
2014/12/08 职场文书
新郎结婚保证书
2015/02/26 职场文书
心术观后感
2015/06/11 职场文书
小学班主任工作随笔
2015/08/15 职场文书
2016思想纪律作风整顿心得体会
2016/01/23 职场文书
优胜劣汰,强者为王——读《鲁滨逊漂流记》有感
2019/08/15 职场文书
Nginx+Tomcat实现负载均衡、动静分离的原理解析
2021/03/31 Servers
python必学知识之文件操作(建议收藏)
2021/05/30 Python
mongodb的安装和开机自启动详细讲解
2021/08/02 MongoDB
MySQL多表查询机制
2022/03/17 MySQL
人物搭配车车超萌联名预备中 【咒术迴战】 ⨯ 【天竺鼠车车】 展开合作
2022/04/11 日漫