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 version 2.7 required, which was not found in the registry
Aug 26 Python
如何利用Fabric自动化你的任务
Oct 20 Python
Python实现时钟显示效果思路详解
Apr 11 Python
PyQt5每天必学之布局管理
Apr 19 Python
python 用lambda函数替换for循环的方法
Jun 09 Python
Python实现的对一个数进行因式分解操作示例
Jun 27 Python
Python实现图像的垂直投影示例
Jan 17 Python
keras和tensorflow使用fit_generator 批次训练操作
Jul 03 Python
详解java调用python的几种用法(看这篇就够了)
Dec 10 Python
秀!学妹看见都惊呆的Python小招数!【详细语言特性使用技巧】
Apr 27 Python
教你怎么用Python实现GIF动图的提取及合成
Jun 15 Python
Python道路车道线检测的实现
Jun 27 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笔试题
2009/08/04 PHP
twig模板获取全局变量的方法
2016/02/05 PHP
如何解决PHP使用mysql_query查询超大结果集超内存问题
2016/03/14 PHP
PHP中的访问修饰符简单比较
2019/02/02 PHP
TP5框架实现一次选择多张图片并预览的方法示例
2020/04/04 PHP
Yii 实现数据加密和解密
2021/03/09 PHP
javascript String 的扩展方法集合
2008/06/01 Javascript
jQuery 操作XML入门
2008/12/25 Javascript
json数据与字符串的相互转化示例
2013/09/18 Javascript
javascript修改表格背景色实例代码分享
2013/12/10 Javascript
javascript判断移动端访问设备并解析对应CSS的方法
2015/02/05 Javascript
window.location.hash知识汇总
2015/11/09 Javascript
jQuery实现获取绑定自定义事件元素的方法
2015/12/02 Javascript
Bootstrap学习笔记之js组件(4)
2016/06/12 Javascript
JS导出PDF插件的方法(支持中文、图片使用路径)
2016/07/12 Javascript
轻松掌握JavaScript单例模式
2016/08/25 Javascript
Angular的自定义指令以及实例
2016/12/26 Javascript
jquery使用iscorll实现上拉、下拉加载刷新
2017/10/26 jQuery
jQuery Datatables表头不对齐的解决办法
2017/11/27 jQuery
JavaScript面试技巧之数组的一些不low操作
2019/03/22 Javascript
详解Python中open()函数指定文件打开方式的用法
2016/06/04 Python
解决Django后台ManyToManyField显示成Object的问题
2019/08/09 Python
Python判断字符串是否为空和null方法实例
2020/04/26 Python
Scrapy项目实战之爬取某社区用户详情
2020/09/17 Python
python 数据类型强制转换的总结
2021/01/25 Python
Pycharm创建python文件自动添加日期作者等信息(步骤详解)
2021/02/03 Python
CSS3实现伪类hover离开时平滑过渡效果示例
2017/08/10 HTML / CSS
CSS3 新增选择器的实例
2019/11/13 HTML / CSS
软件测试面试题
2015/10/21 面试题
客服文员岗位职责
2013/11/29 职场文书
酒店保安领班职务说明书
2014/03/04 职场文书
基督教婚礼主持词
2014/03/14 职场文书
运动会演讲稿300字
2014/08/25 职场文书
师德师风自我剖析材料
2014/09/27 职场文书
初中英语教师个人工作总结
2015/02/09 职场文书
教你怎么用PyCharm为同一服务器配置多个python解释器
2021/05/31 Python