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中fileno()方法的使用
May 24 Python
100行python代码实现跳一跳辅助程序
Jan 15 Python
pandas object格式转float64格式的方法
Apr 10 Python
python遍历小写英文字母的方法
Jan 02 Python
Pytorch实现GoogLeNet的方法
Aug 18 Python
详解使用Python下载文件的几种方法
Oct 13 Python
python sorted方法和列表使用解析
Nov 18 Python
python字典key不能是可以是啥类型
Aug 04 Python
如何利用Python动态模拟太阳系运转
Sep 04 Python
Python如何在bool函数中取值
Sep 21 Python
分享unittest单元测试框架中几种常用的用例加载方法
Dec 02 Python
Python3.9.0 a1安装pygame出错解决全过程(小结)
Feb 02 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缓存类分享     php缓存机制
2014/01/22 PHP
PHP伪造来源HTTP_REFERER的方法实例详解
2015/07/06 PHP
PHP AjaxForm提交图片上传并显示图片源码
2016/11/29 PHP
JavaScript实现Sleep函数的代码
2007/03/04 Javascript
Jquery 基础学习笔记
2009/05/29 Javascript
js 关于=+与+=日期函数使用说明(赋值运算符)
2011/11/15 Javascript
jQuery学习笔记之控制页面实现代码
2012/02/27 Javascript
js读写cookie实现一个底部广告浮层效果的两种方法
2013/12/29 Javascript
Javascript aop(面向切面编程)之around(环绕)分析
2015/05/01 Javascript
微信小程序 框架详解及实例应用
2016/09/26 Javascript
JavaScript文件的同步和异步加载的实现代码
2017/08/19 Javascript
纯js实现画一棵树的示例
2017/09/05 Javascript
一个有意思的鼠标点击文字特效jquery代码
2017/09/23 jQuery
React Native基础入门之初步使用Flexbox布局
2018/07/02 Javascript
详解微信小程序开发聊天室—实时聊天,支持图片预览
2019/05/20 Javascript
Node.js API详解之 tty功能与用法实例分析
2020/04/27 Javascript
微信小程序实现上拉加载功能示例【加载更多数据/触底加载/点击加载更多数据】
2020/05/29 Javascript
Javascript如何实现扩充基本类型
2020/08/26 Javascript
[32:47]完美世界DOTA2联赛 GXR vs IO 第二场 11.07
2020/11/09 DOTA
python实现人脸识别代码
2017/11/08 Python
教你用 Python 实现微信跳一跳(Mac+iOS版)
2018/01/04 Python
如何安装多版本python python2和python3共存以及pip共存
2018/09/18 Python
详解分布式任务队列Celery使用说明
2018/11/29 Python
python实现转圈打印矩阵
2019/03/02 Python
python模块导入的方法
2019/10/24 Python
python 数据分析实现长宽格式的转换
2020/05/18 Python
CSS3 animation实现逐帧动画效果
2016/06/02 HTML / CSS
The North Face意大利官网:服装、背包和鞋子
2020/06/17 全球购物
如何实现一个自定义类的序列化
2012/05/22 面试题
大学竞选班长演讲稿
2014/04/24 职场文书
森林防火宣传标语
2014/06/27 职场文书
道路交通事故赔偿协议书
2014/10/24 职场文书
2016党员学习心得体会范文
2016/01/23 职场文书
MySQL令人咋舌的隐式转换
2021/04/05 MySQL
大脑的记忆过程在做数据压缩,不同图形也有共同的记忆格式
2022/04/29 数码科技
python playwright之元素定位示例详解
2022/07/23 Python