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 中文字符串的处理实现代码
Oct 25 Python
跟老齐学Python之折腾一下目录
Oct 24 Python
Python、Javascript中的闭包比较
Feb 04 Python
python图书管理系统
Apr 05 Python
Python为何不能用可变对象作为默认参数的值
Jul 01 Python
python控制台实现tab补全和清屏的例子
Aug 20 Python
python matplotlib 画dataframe的时间序列图实例
Nov 20 Python
python函数中将变量名转换成字符串实例
May 11 Python
python文件排序的方法总结
Sep 13 Python
Python实例教程之检索输出月份日历表
Dec 16 Python
Django实现WebSocket在线聊天室功能(channels库)
Sep 25 Python
Python正则表达式中flags参数的实例详解
Apr 01 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
改进的IP计数器
2006/10/09 PHP
用PHP和ACCESS写聊天室(四)
2006/10/09 PHP
php ftp文件上传函数(基础版)
2010/06/03 PHP
10个超级有用值得收藏的PHP代码片段
2015/01/22 PHP
PHP实现阿里大鱼短信验证的实例代码
2017/07/10 PHP
Javascript 日期对象Date扩展方法
2009/05/30 Javascript
基于node.js的快速开发透明代理
2010/12/25 Javascript
解决js下referer兼容各大浏览器的方法
2014/11/03 Javascript
jQuery设置和移除文本框默认值的方法
2015/03/09 Javascript
Jquery针对tr td的一些实用操作方法(必看篇)
2016/10/05 Javascript
JS原生轮播图的简单实现(推荐)
2017/07/22 Javascript
Vue异步加载about组件
2017/10/31 Javascript
使用Vue实现图片上传的三种方式
2018/07/17 Javascript
vue 地区选择器v-distpicker的常用功能
2019/07/23 Javascript
微信小程序scroll-view的滚动条设置实现
2020/03/02 Javascript
JavaScript如何判断对象有某属性
2020/07/03 Javascript
使用Typescript开发微信小程序的步骤详解
2021/01/12 Javascript
异步任务队列Celery在Django中的使用方法
2018/06/07 Python
Python 数值区间处理_对interval 库的快速入门详解
2018/11/16 Python
Python查找最长不包含重复字符的子字符串算法示例
2019/02/13 Python
Ubuntu18.04下python版本完美切换的解决方法
2019/06/14 Python
Pytorch加载部分预训练模型的参数实例
2019/08/18 Python
Pandas时间序列:时期(period)及其算术运算详解
2020/02/25 Python
python中如何进行连乘计算
2020/05/28 Python
解析Tensorflow之MNIST的使用
2020/06/30 Python
Python爬虫之Selenium多窗口切换的实现
2020/12/04 Python
纯css3实现的动画按钮的实例教程
2014/11/17 HTML / CSS
NFL加拿大官方网上商店:NHLShop.ca
2019/03/12 全球购物
King Apparel官网:英国街头服饰品牌
2019/09/05 全球购物
狼和鹿教学反思
2014/02/05 职场文书
电台编导求职信
2014/05/06 职场文书
公务员上班玩游戏检讨书
2014/09/17 职场文书
对外汉语专业大学生职业生涯规划书
2014/10/11 职场文书
社区三八妇女节活动总结
2015/02/06 职场文书
分享几个实用的CSS代码块
2022/06/10 HTML / CSS
css中:last-child不生效的解决方法
2022/08/05 HTML / CSS