Python实现二叉搜索树

二叉搜索树(二叉查找树,Binary Search Tree)是一种特殊的二叉树,又称为排序二叉树、有序二叉树。

二叉搜索树具有如下特性:

1. 如果二叉树的左子树不为空,则左子树上所有节点的值均小于它的根节点的值。

2. 如果二叉树的右子树不为空,则右子树上所有节点的值均大于它的根节点的值。

3. 如果独立地看,左子树、右子树也分别为二叉搜索树,用递归的思想,直到树的叶节点。

下图是一个二叉搜索树的例子,可以参照图片来核对这三条特性,本文使用Python来实现二叉搜索树。

一、实现节点类

所有树结构都是由一个一个的节点构成的,本文使用链式的方式来实现二叉搜索树,所以先实现一个节点类。

# coding=utf-8
class Node(object):"""节点类"""def __init__(self, data, left_child=None, right_child=None):self.data = dataself.parent = Noneself.left_child = left_childself.right_child = right_child

在二叉树中添加节点时,要先创建节点,有了节点类,实例化一个节点类的实例即可,节点初始化时是一个孤立的节点,指向的父节点、左子节点、右子节点都为空。将节点“挂”到树上(添加到树中)后,才属于树的一部分。

二、实现二叉搜索树类

实现一个二叉搜索树的类 SearchBinaryTree,创建二叉搜索树时,实例化一个 SearchBinaryTree 类的实例即可。

class SearchBinaryTree(object):"""二叉树类"""def __init__(self):self.__root = Noneself.prefix_branch = '├'self.prefix_trunk = '|'self.prefix_leaf = '└'self.prefix_empty = ''self.prefix_left = '─L─'self.prefix_right = '─R─'def is_empty(self):return not self.__root@propertydef root(self):return self.__root@root.setterdef root(self, value):self.__root = value if isinstance(value, Node) else Node(value)def show_tree(self):if self.is_empty():print('空二叉树')returnprint('-' * 20)print(self.__root.data)self.__print_tree(self.__root)print('-' * 20)def levelorder_traversal(self):"""层序遍历"""if self.is_empty():returnqueue = list()queue.insert(0, self.__root)while len(queue):cur = queue.pop()print(cur.data, end=' ')if cur.left_child is not None:queue.insert(0, cur.left_child)if cur.right_child is not None:queue.insert(0, cur.right_child)print()def preorder_traversal(self, node):"""先序遍历"""if node is None:returnprint(node.data, end=' ')self.preorder_traversal(node.left_child)self.preorder_traversal(node.right_child)def inorder_traversal(self, node):"""中序遍历"""if node is None:returnself.inorder_traversal(node.left_child)print(node.data, end=' ')self.inorder_traversal(node.right_child)def postorder_traversal(self, node):"""后序遍历"""if node is None:returnself.postorder_traversal(node.left_child)self.postorder_traversal(node.right_child)print(node.data, end=' ')def __print_tree(self, node, prefix=None):if prefix is None:prefix, prefix_left_child = '', ''else:prefix = prefix.replace(self.prefix_branch, self.prefix_trunk)prefix = prefix.replace(self.prefix_leaf, self.prefix_empty)prefix_left_child = prefix.replace(self.prefix_leaf, self.prefix_empty)if self.has_child(node):if node.right_child is not None:print(prefix + self.prefix_branch + self.prefix_right + str(node.right_child.data))if self.has_child(node.right_child):self.__print_tree(node.right_child, prefix + self.prefix_branch + ' ')else:print(prefix + self.prefix_branch + self.prefix_right)if node.left_child is not None:print(prefix + self.prefix_leaf + self.prefix_left + str(node.left_child.data))if self.has_child(node.left_child):prefix_left_child += '  'self.__print_tree(node.left_child, self.prefix_leaf + prefix_left_child)else:print(prefix + self.prefix_leaf + self.prefix_left)def has_child(self, node):return node.left_child is not None or node.right_child is not Nonedef __str__(self):return str(self.__class__)

代码中实现了判断二叉树是否为空的 is_empty() 方法,一对供实例对象获取和设置根节点的 root() 方法,按树形结构打印二叉树的 show_tree() 方法,二叉树的广度优先遍历方法和三种深度优先遍历方法,这里就不一一介绍了,可以参考本专栏中的其他文章。

三、二叉搜索树添加节点

本文开头列出了二叉搜索树的特性,向二叉搜索树中添加节点后,一定要保证二叉搜索树仍然满足这些特性。所以,在添加节点前,要先判断新节点中的数值大小,根据数值的大小来找到节点添加的位置。

向二叉搜索树中添加新节点的过程为:

1. 如果二叉搜索树为空树,则将新节点添加在根节点的位置。

2. 如果二叉搜索树非空,根据新节点中的数值大小,分为如下几种情况:

2.1 如果新节点中的数值小于根节点中的数值,则将新节点添加到二叉搜索树的左子树中。

2.2 如果新节点中的数值大于根节点中的数值,则将新节点添加到二叉搜索树的右子树中。

2.3 如果新节点中的数值等于根节点中的数值,按需进行处理,可以自己选择不添加、添加到左子树中或添加到右子树中,本文按不添加处理。

3. 左子树和右子树也是二叉搜索树,所以递归地使用 1,2 的步骤在左子树和右子树中找到新节点的添加位置,添加节点。

    def insert(self, root, value):"""二叉搜索树插入节点-递归"""node = value if isinstance(value, Node) else Node(value)if self.is_empty():self.root = nodereturnif root is None:root = nodeelif node.data < root.data:root.left_child = self.insert(root.left_child, value)root.left_child.parent = rootelif node.data > root.data:root.right_child = self.insert(root.right_child, value)root.right_child.parent = rootreturn root

insert(root, value): 二叉搜索树添加节点的递归实现。这个方法就是根据上面的添加过程,先找到添加新节点的位置,然后添加节点。方法中从根节点开始,递归地判断左子树或右子树的根节点,当遇到子树的根节点为空时,就找到了添加新节点的位置。每次判断都将当前判断的节点返回,作为下一次递归的入参。

对于这个递归的过程,如果觉得很绕,可以按这个过程从一棵空树开始添加,画一下树中节点一个个增加的过程,就可以理解了。

当然,也可以使用非递归的方式来实现。非递归的添加过程如下:

1. 如果二叉搜索树为空树,则将新节点添加在根节点的位置。

2. 如果二叉搜索树非空,先定义一个变量 current_node 表示当前节点,最开始的当前节点 current_node 为根节点。

然后使用一个无限循环,添加节点后退出无限循环。在无限循环中,根据新节点中的数值大小,分为如下几种情况:

2.1 如果新节点中的数值小于当前节点中的数值,则判断当前节点是否有左子节点。没有左子节点就直接添加新节点,退出循环,有左子节点则将当前节点赋值为左子节点,进入下一次循环。下一次循环中,当前节点中的值已经发生了变化,会重新比较新节点中的值与当前节点中的值的大小。

2.2 如果新节点中的数值大于当前节点中的数值,则判断当前节点是否有右子节点,原理同左子节点。

2.3 如果新节点中的数值等于根节点中的数值,按需进行处理,可以自己选择不添加、添加到左子树中或添加到右子树中,本文按不添加处理,直接退出无限循环即可。

    def insert_normal(self, value):"""二叉搜索树插入节点-非递归"""node = value if isinstance(value, Node) else Node(value)if self.is_empty():self.root = nodereturnelse:current_node = self.rootwhile True:if node.data < current_node.data:if current_node.left_child:current_node = current_node.left_childelse:current_node.left_child = nodenode.parent = current_nodebreakelif node.data > current_node.data:if current_node.right_child:current_node = current_node.right_childelse:current_node.right_child = nodenode.parent = current_nodebreakelse:break

insert_normal(value): 二叉搜索树添加节点的非递归实现。理解了上面描述的非递归添加过程,代码就很好理解了,代码完全是按上面的过程实现的。

在上面的递归方式和非递归方式添加的方法中,都支持传入一个节点或传入节点中保存的数值。

if __name__ == '__main__':tree = SearchBinaryTree()data = [50, 77, 55, 29, 10, 50, 30, 66, 18, 80, 51, 18, 90]for i in data:# tree.insert(tree.root, i)tree.insert_normal(i)tree.show_tree()

运行结果:

--------------------
50
├─R─77
| ├─R─80
| | ├─R─90
| | └─L─
| └─L─55
|   ├─R─66
|   └─L─51
└─L─29├─R─30└─L─10├─R─18└─L─
--------------------

添加数据后的二叉搜索树结构如下图,在我提供的原始数据列表中,有两个 50 和 18 ,会出现新节点中的数值与已有节点中的数值相同的情况,可以看到并没有重复添加。

代码里已经实现了二叉搜索树的广度优先遍历和深度优先遍历,现在添加了数据,可以看一下遍历的结果。

    print('层次遍历: ', end='')tree.levelorder_traversal()print('先序遍历: ', end='')tree.preorder_traversal(tree.root)print()print('中序遍历: ', end='')tree.inorder_traversal(tree.root)print()print('后序遍历: ', end='')tree.postorder_traversal(tree.root)print()

运行结果:

层次遍历: 50 29 77 10 30 55 80 18 51 66 90
先序遍历: 50 29 10 18 30 77 55 51 66 80 90
中序遍历: 10 18 29 30 50 51 55 66 77 80 90
后序遍历: 18 10 30 29 51 66 55 90 80 77 50 

四、二叉搜索树的搜索、最大值和最小值

实现二叉搜索树中的搜索功能,返回最大值和返回最小值的方法。

    def search(self, root, data):"""二叉搜索树的查询操作"""if root is None:return Falseif root.data == data:return Trueelif data < root.data:return self.search(root.left_child, data)elif data > root.data:return self.search(root.right_child, data)def get_max(self, root):"""查找二叉搜索树的最大值"""if self.is_empty():returnreturn self.get_max(root.right_child) if root.right_child else root.datadef get_min(self, root):"""查找二叉搜索树的最小值"""if self.is_empty():returnreturn self.get_min(root.left_child) if root.left_child else root.data

search(root, data): 判断指定数值是否存在二叉搜索树中。如果二叉搜索树是一棵空树,则直接返回 False,如果二叉搜索树非空,当根节点中的数值等于指定数值时,则说明此数值存在二叉搜索树中,返回 True,其他情况根据数值的大小递归地在左子树或右子树中进行搜索。

get_max(root): 返回二叉搜索树中的最大值。如果二叉搜索树为空,则没有最大值,直接返回。如果二叉搜索树非空,当存在右子树时,递归地到右子树中搜索最大值,否则直接返回根节点中的数值。最大值不可能出现在左子树中。

get_min(root): 返回二叉搜索树中的最小值。如果二叉搜索树为空,则没有最小值,直接返回。如果二叉搜索树非空,当存在左子树时,递归地到左子树中搜索最小值,否则直接返回根节点中的数值。最小值不可能出现在右子树中。

    print("查询结果为:", tree.search(tree.root, 50))print("查询结果为:", tree.search(tree.root, 500))print("二叉搜素树的最大值是:", tree.get_max(tree.root))print("二叉搜素树的最小值是:", tree.get_min(tree.root))

运行结果:

查询结果为: True
查询结果为: False
二叉搜素树的最大值是: 90
二叉搜素树的最小值是: 10

五、完整代码

# coding=utf-8
class Node(object):"""节点类"""def __init__(self, data, left_child=None, right_child=None):self.data = dataself.parent = Noneself.left_child = left_childself.right_child = right_childclass SearchBinaryTree(object):"""二叉树类"""def __init__(self):self.__root = Noneself.prefix_branch = '├'self.prefix_trunk = '|'self.prefix_leaf = '└'self.prefix_empty = ''self.prefix_left = '─L─'self.prefix_right = '─R─'def is_empty(self):return not self.__root@propertydef root(self):return self.__root@root.setterdef root(self, value):self.__root = value if isinstance(value, Node) else Node(value)def show_tree(self):if self.is_empty():print('空二叉树')returnprint('-' * 20)print(self.__root.data)self.__print_tree(self.__root)print('-' * 20)def insert(self, root, value):"""二叉搜索树插入节点-递归"""node = value if isinstance(value, Node) else Node(value)if self.is_empty():self.root = nodereturnif root is None:root = nodeelif node.data < root.data:root.left_child = self.insert(root.left_child, value)root.left_child.parent = rootelif node.data > root.data:root.right_child = self.insert(root.right_child, value)root.right_child.parent = rootreturn rootdef insert_normal(self, value):"""二叉搜索树插入节点-非递归"""node = value if isinstance(value, Node) else Node(value)if self.is_empty():self.root = nodereturnelse:current_node = self.rootwhile True:if node.data < current_node.data:if current_node.left_child:current_node = current_node.left_childelse:current_node.left_child = nodenode.parent = current_nodebreakelif node.data > current_node.data:if current_node.right_child:current_node = current_node.right_childelse:current_node.right_child = nodenode.parent = current_nodebreakelse:breakdef search(self, root, data):"""二叉搜索树的查询操作"""if root is None:return Falseif root.data == data:return Trueelif data < root.data:return self.search(root.left_child, data)elif data > root.data:return self.search(root.right_child, data)def get_max(self, root):"""查找二叉搜索树的最大值"""if self.is_empty():returnreturn self.get_max(root.right_child) if root.right_child else root.datadef get_min(self, root):"""查找二叉搜索树的最小值"""if self.is_empty():returnreturn self.get_min(root.left_child) if root.left_child else root.datadef levelorder_traversal(self):"""层序遍历"""if self.is_empty():returnqueue = list()queue.insert(0, self.__root)while len(queue):cur = queue.pop()print(cur.data, end=' ')if cur.left_child is not None:queue.insert(0, cur.left_child)if cur.right_child is not None:queue.insert(0, cur.right_child)print()def preorder_traversal(self, node):"""先序遍历"""if node is None:returnprint(node.data, end=' ')self.preorder_traversal(node.left_child)self.preorder_traversal(node.right_child)def inorder_traversal(self, node):"""中序遍历"""if node is None:returnself.inorder_traversal(node.left_child)print(node.data, end=' ')self.inorder_traversal(node.right_child)def postorder_traversal(self, node):"""后序遍历"""if node is None:returnself.postorder_traversal(node.left_child)self.postorder_traversal(node.right_child)print(node.data, end=' ')def __print_tree(self, node, prefix=None):if prefix is None:prefix, prefix_left_child = '', ''else:prefix = prefix.replace(self.prefix_branch, self.prefix_trunk)prefix = prefix.replace(self.prefix_leaf, self.prefix_empty)prefix_left_child = prefix.replace(self.prefix_leaf, self.prefix_empty)if self.has_child(node):if node.right_child is not None:print(prefix + self.prefix_branch + self.prefix_right + str(node.right_child.data))if self.has_child(node.right_child):self.__print_tree(node.right_child, prefix + self.prefix_branch + ' ')else:print(prefix + self.prefix_branch + self.prefix_right)if node.left_child is not None:print(prefix + self.prefix_leaf + self.prefix_left + str(node.left_child.data))if self.has_child(node.left_child):prefix_left_child += '  'self.__print_tree(node.left_child, self.prefix_leaf + prefix_left_child)else:print(prefix + self.prefix_leaf + self.prefix_left)def has_child(self, node):return node.left_child is not None or node.right_child is not Nonedef __str__(self):return str(self.__class__)if __name__ == '__main__':tree = SearchBinaryTree()data = [50, 77, 55, 29, 10, 50, 30, 66, 18, 80, 51, 18, 90]for i in data:# tree.insert(tree.root, i)tree.insert_normal(i)tree.show_tree()print('层次遍历: ', end='')tree.levelorder_traversal()print('先序遍历: ', end='')tree.preorder_traversal(tree.root)print()print('中序遍历: ', end='')tree.inorder_traversal(tree.root)print()print('后序遍历: ', end='')tree.postorder_traversal(tree.root)print()print("查询结果为:", tree.search(tree.root, 50))print("查询结果为:", tree.search(tree.root, 500))print("二叉搜素树的最大值是:", tree.get_max(tree.root))print("二叉搜素树的最小值是:", tree.get_min(tree.root))

Python实现二叉搜索树相关推荐

  1. Python实现二叉搜索树的删除功能

    Python实现二叉搜索树的删除功能 二叉搜索树(二叉查找树,Binary Search Tree)又称为排序二叉树.有序二叉树. 二叉搜索树的实现可以参考:https://blog.csdn.net ...

  2. python实现二叉搜索树_python实现二叉查找树

    这次用完成的是二叉树,是一种简单的树型结构.同样使用python实现 多的不说了,上代码吧. # -*- coding: cp936 -*- #---------------------------- ...

  3. 【数据结构】二叉搜索树的python实现

    [数据结构]二叉搜索树的python实现 二叉搜索树是以二叉树来组织的,对于一个二叉搜索树的节点,其左子树节点的元素值都不大于该节点元素值,其右子树节点的元素值都不小于该节点的元素值. 首先定义一个初 ...

  4. 二叉树查找python_二叉搜索树的python实现

    介绍 二叉查找树(Binary Search Tree),也称为二叉搜索树.有序二叉树或排序二叉树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节 ...

  5. 笨办法学 Python · 续 练习 20:二叉搜索树

    练习 20:二叉搜索树 原文:Exercise 20: Binary Search Trees 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 在本练习中,我将让你将数据结构的中 ...

  6. BST二叉搜索树插入节点建树并找出不平衡节点,networkx,Python

    BST二叉搜索树插入节点建树并找出失衡节点,networkx,Python import randomfrom matplotlib import pyplot as plt import netwo ...

  7. python二叉搜索树建立_700. 二叉搜索树的搜索(Python)

    题目 难度:★☆☆☆☆ 类型:二叉树 给定二叉搜索树(BST)的根节点和一个值. 你需要在BST中找到节点值等于给定值的节点. 返回以该节点为根的子树. 如果节点不存在,则返回 NULL. 例如, 给 ...

  8. 有序链表转换二叉搜索树Python解法

    给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1. 来源:力扣(Lee ...

  9. 将有序数组转换为二叉搜索树Python解法

    给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树. 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树. 来源: ...

最新文章

  1. 全球首个AI驾校教练+驾照考官已上岗,装手机里就能用,再也不怕挨教练骂了...
  2. Java开发知识体系!我用2个月的时间破茧成蝶
  3. 用AutoML找到更小、更快、更好的模型,谷歌开源Model Search
  4. oracle查询用户下所有表名称
  5. 勒索病毒引出重大话题:公有云比私有云更安全?
  6. R+NLP︱text2vec包——BOW词袋模型做监督式情感标注案例(二,情感标注)
  7. 享元模式在 Java Integer 中的应用
  8. MapInfo地图查询的简单实现
  9. linux 游戏手柄 驱动,forev手柄驱动
  10. app逆向入门分析——破解某APP登陆请求参数
  11. 大牛手把手带你!mysql视频教程百度网盘
  12. 谨记:只看背驰会死翘翘的!
  13. 关于音频情感分类的随笔(3)
  14. AVS3中的intra string copy(ISC)
  15. gpu版本pytorch配置
  16. JavaScript--轮播图_带计时器
  17. C#中invoke和beginInvoke
  18. axios 和洋葱模型中间件
  19. java网络学习之 jca体系概述(12)
  20. Transformer家族5 -- 推理加速(Faster-Transformer、TurboTransformers)

热门文章

  1. mysql show
  2. Gulp构建Angularjs应用
  3. Windows下Redmine插件安装
  4. Python 实现网络爬虫小程序
  5. MVC3.0 将网站设为首页和加为收藏的实现(IE/Firefox)
  6. TypeScript入门教程 之 类/抽象类/构造器/Getter/Setter
  7. Docker教程(四) Docker镜像构建
  8. Debian/Ubuntu系统下,apt-get update 、apt-get upgrade 、apt-get dist-upgrade 命令之间的区别
  9. donotage标记、MTU及MTU不匹配问题、OSPF邻居状态记录
  10. SpringMVC 解决中文乱码的过滤器