二叉树的python可视化和常用操作代码

时间:2022-12-18 15:46:03

二叉树是一个重要的数据结构, 本文基于"二叉查找树"的python可视化 pybst 包, 做了一些改造, 可以支持更一般的"二叉树"可视化. 关于二叉树和二叉查找树的概念以及常用操作和算法基础, 可以看后面的参考文章.

===================================
二叉查找树可视化包 pybst
===================================
pypi 有一个"二叉查找树"的可视化的package, 是 pybst 包, 该包依赖 matplotlib 和 networkx, 所以推荐在 Anaconda 发行版上安装.

以下代码可以直接在 dreampie shell中执行

# demo1: 简单测试示例

# 导入指定类和函数
from pybst.bstree import BSTree
from pybst.draw import plot_tree # 创建一个树
tree=BSTree() tree.insert(10, '')
"""
insert()方法说明: 增加一个节点(key为10, value为a), key 必须是数值, value 看起来没什么用, 直接赋空字符串即可.
因为没有指定 parent 参数, 而且是第一个没有指定 parent 的调用, 所以新节点为根节点.
在根节点生成后, 如调用 insert() 时仍没有指定 parent 的话, bst 包将按照二叉查找树的规则, 自动在合适的节点上增加子节点.
但注意该函数返回值为空, 而不是新生成的节点, 要获得新节点, 需要使用get_node()方法.
""" # 获取key=10的节点
parent_node=tree.get_node(10) # 在key=10的节点上增加子节点, 因为bst包是二叉查找树, 所以如果三次指定了同一个parent_node,
# 第3次新增的节点将是parent_node的孙子节点, 而不是直接子节点
tree.insert(11, '', parent_node) # 二叉查找树可视化, 该树共两个节点: 10 和 11
plot_tree(tree)
# demo2: 一个稍微复杂的示例

# 创建一个树
tree=BSTree()
tree.insert(90, '') node_90=tree.get_node(90)
tree.insert(50, '', node_90)
tree.insert(150, '', node_90) node_50=tree.get_node(50)
tree.insert(20, '', node_50)
tree.insert(75, '', node_50) node_20=tree.get_node(20)
tree.insert(5, '', node_20)
tree.insert(25, '', node_20) node_75=tree.get_node(75)
tree.insert(66, '', node_75)
tree.insert(88, '', node_75)
tree.insert(98, '', node_75) # 注意98这个节点将自动会接在88节点下, 而不是75节点下. # 二叉查找树可视化
plot_tree(tree)

===================================
让 pybst 包支持普通二叉树
===================================

因为 bst 包自动会按照"二叉查找树"的规则排列节点, 比如key小的话, 会放在左边, key多的话, 会放在右边, 也会自动选择合适的父节点.
所以不能支持普通的二叉树的可视化, 我对 pybst 包 bstree.py 做了修改, 可以支持普通的二叉树的可视化.

-----------------------------------
增加 binarytree.py 模块
-----------------------------------

file bstree.py -> binarytree.py , 最终也放到 site-packages\pybst\ 目录下.
class BSTree --> BinaryTree
并为新的 BinaryTree 类增加下面 3 个方法, 这些方法修改自 BSTree.get_node() 和 insert() 方法.

    def get_node_for_binary_tree(self,key,*args):
"""
T.get_node(key,...) -> Node. Produces the Node in T with key
attribute key. If there is no such node, produces None.
"""
if len(args) == 0:
start = self.Root
else:
start = args[0] if not start:
return None if key == start.key:
return start
else:
node = self.get_node_for_binary_tree(key, start.right)
if node:
return node
else:
node = self.get_node_for_binary_tree(key, start.left)
return node def insert_right(self,key,value,*args):
"""
T.insert(key,value...) <==> T[key] = value. Inserts
a new Node with key attribute key and value attribute
value into T.
"""
if not isinstance(key,(int,long,float)):
raise TypeError(str(key) + " is not a number")
else:
if not self.Root:
self.Root = Node(key,value)
elif len(args) == 0:
if not self.get_node_for_binary_tree(key,self.Root):
self.insert(key,value,self.Root)
else:
child = Node(key,value)
parent = args[0]
if not parent.right:
parent.right = child
child.parent = parent
else:
self.insert(key,value,parent.right) def insert_left(self,key,value,*args):
"""
T.insert(key,value...) <==> T[key] = value. Inserts
a new Node with key attribute key and value attribute
value into T.
"""
if not isinstance(key,(int,long,float)):
raise TypeError(str(key) + " is not a number")
else:
if not self.Root:
self.Root = Node(key,value)
elif len(args) == 0:
if not self.get_node_for_binary_tree(key,self.Root):
self.insert(key,value,self.Root)
else:
child = Node(key,value)
parent = args[0]
if not parent.left:
parent.left = child
child.parent = parent
else:
self.insert(key,value,parent.left)

-----------------------------------
普通二叉树可视化的 TreeNode class 和 util 方法
-----------------------------------
# 文件名 binary_tree_util.py

# TreeNode class
class TreeNode(object):
def __init__(self, key, left=None, right=None):
self.key=key
self.left=left
self.right=right def __str__(self):
return str(self.key) # visualization
from pybst.binarytree import BinaryTree
from pybst.draw import plot_tree def my_preorder_traverse(tree, node, parent_node, is_left, combine_action):
print(node)
if combine_action:
combine_action(tree, node, parent_node, is_left)
if node.left:
is_left=True
my_preorder_traverse(tree, node.left, node, is_left, combine_action)
if node.right:
is_left=False
my_preorder_traverse(tree, node.right, node, is_left, combine_action) def my_combine_node(tree, node, parent_node=None, is_left=True):
if parent_node:
parent_node_bt=tree.get_node_for_binary_tree(parent_node.key)
if is_left:
tree.insert_left(node.key, '', parent_node_bt)
else:
tree.insert_right(node.key, '', parent_node_bt)
else:
tree.insert(node.key, '') def my_draw_bt(root_node):
tree=BinaryTree()
combine_node=my_combine_node
# 使用前序遍历的方法将各节点串成一个bst包能支持的tree
my_preorder_traverse(tree, root_node, parent_node=None, is_left=True, combine_action=combine_node)
if combine_node:
plot_tree(tree) # 测试可视化效果
root=TreeNode(4,
TreeNode(2, TreeNode(1), TreeNode(3)),
TreeNode(7, TreeNode(6), TreeNode(8))
)
my_draw_bt(root) root=TreeNode(4,
TreeNode(7, TreeNode(8), TreeNode(6)),
TreeNode(2, TreeNode(3), TreeNode(1))
)
my_draw_bt(root)

===================================
二叉树翻转 reverse
===================================

# reverse
def reverse(node):
if node:
node.left, node.right=node.right, node.left
if node.left:
node.left=reverse(node.left)
if node.right:
node.right=reverse(node.right)
return node # 测试revese
root=TreeNode(4,
TreeNode(2, TreeNode(1), TreeNode(3)),
TreeNode(7, TreeNode(6), TreeNode(8))
)
my_draw_bt(root)
root=reverse(root)
my_draw_bt(root)

===================================
二叉树遍历
===================================

def preorder(node):
print(node)
if node.left:
preorder(node.left)
if node.right:
preorder(node.right) def inorder(node):
if node.left:
inorder(node.left)
print(node)
if node.right:
inorder(node.right) def postorder(node):
if node.left:
postorder(node.left)
if node.right:
postorder(node.right)
print(node) # 测试revese
root=TreeNode(4,
TreeNode(2, TreeNode(1), TreeNode(3)),
TreeNode(7, TreeNode(6), TreeNode(8))
)
my_draw_bt(root)
preorder(root)
inorder(root)
postorder(root)

===================================
二叉树的查找
===================================

def find(node, key):
if node:
if node.key==key:
return node
elif key<node.key:
return find(node.left,key)
else:
return find(node.right,key)
return node def find_min(node):
if node:
if node.left:
return find_min(node.left)
else:
return node
else:
return None def find_max(node):
if node:
if node.right:
return find_max(node.right)
else:
return node
else:
return None # 测试搜素
root=TreeNode(4,
TreeNode(2, TreeNode(1), TreeNode(3)),
TreeNode(7, TreeNode(6), TreeNode(8))
)
node=find(root, 3)
node=find(root, 500) find_min(root)
find_max(root)

===================================
参考文献: 二叉树的概念
===================================
http://hujiaweibujidao.github.io/python/ , 很全面,可以算作是 Python 算法导论
https://www.the5fire.com/python-invert-binary-tree.html , 那个著名的面试题,反转二叉树的python版本
http://www.cnblogs.com/gaochundong/p/binary_search_tree.html, 各种二叉树的概念, 以及二叉查找的增删和遍历
http://btv.melezinek.cz/binary-search-tree.html 在网页上可视化显示二叉查找树的各种算法
http://www.i3geek.com/archives/702 , 二叉树——二叉查找树的增、删、查
http://www.cnblogs.com/hlxs/archive/2010/11/19/2087987.html
创建二叉查找树、查找二叉树中的某个节点、删除某个节点、
新增节点、查找某个节点的父节点、查找最小节点
对二叉树进行前序遍历、中序遍历、后序遍

二叉树的python可视化和常用操作代码的更多相关文章

  1. legend3---lavarel常用操作代码2

    legend3---lavarel常用操作代码2 一.总结 一句话总结: 对于王思cong被执法人的感悟:失意时 莫心伤,得意时 莫膨胀 1.lavarel自动事务? DB::transaction方 ...

  2. legend3---lavarel常用操作代码

    legend3---lavarel常用操作代码 一.总结 一句话总结: 要自己总结一下常用代码,这样才方便,也才有收获 1.路由示例:Route::get('/login','Home\Login\L ...

  3. legend3---Homestead常用操作代码

    legend3---Homestead常用操作代码 一.总结 一句话总结: 在虚拟机里面改变文件windows里面也会变,在windows里面改变虚拟机里面也会变,所以可以在windows里面编程或者 ...

  4. c&plus;&plus; MFC图像处理CImage类常用操作代码

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9598974.html MFC图像处理CImage类常用操作 CImage类头文件为#inclu ...

  5. 初识python: 字符串常用操作

    直接上代码示例: #!/user/bin env python # author:Simple-Sir # time:20180914 # 字符串常用操作 name = 'lzh lyh' print ...

  6. Python数据类型及常用操作

    Python字符串类型 1.用途: 用来记录有描述性的状态.比如:人名,地址等. 2.定义方式: 创建字符串非常简单,在‘ ’,“ ”,‘’‘ ’‘’内一填写一系列的字符例如:msg='hello' ...

  7. Python字符串的常用操作学习

    >>> name = "I love my job!" >>> name.capitalize() #首字母大写 'I love my job! ...

  8. Python集合的常用操作

    字典常用的就是,他的去重. set集合是python的一个基本数据类型. set中的元素是不重复的.⽆无序的.⾥面的元素必须是可hash的(int, str, tuple,bool). 我们可以这样来 ...

  9. python os 模块常用操作

    python 2.7 os 常用操作 官方document链接 文件和目录 os.access(path, mode) 读写权限测试 应用: try: fp = open("myfile&q ...

随机推荐

  1. centos7 docker activemq

    / cd /home/activemq// wget http://apache.fayea.com/activemq/5.13.3/apache-activemq-5.13.3-bin.tar.gz ...

  2. ASP&period;NET MVC必知必会知识点总结(一)

    一.URL Routing 1.添加URL路由映射的一般方法(在RegisterRoutes方法中添加): //第一种(建议采用这种): routes.MapRoute( "MyRoute& ...

  3. DFX 安全测试-- 告诉你什么是XSS、sql注入?POST和GET的区别&period;&period;&period;&period;

    1.用户权限测试 (1) 用户权限控制 1) 用户权限控制主要是对一些有权限控制的功能进行验证 2) 用户A才能进行的操作,B是否能够进行操作(可通过窜session,将在下面介绍) 3)只能有A条件 ...

  4. Java学习之Hessian通信基础

    一.首先先说Hessian是什么?    Hessian:hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能,相比WebService,Hessian更简 ...

  5. hibernate反向生成映射文件报错

    报错原因:可能是你的数据库里的某个表没设置主键.

  6. 第五课,T语言转义字符()&lpar;版本5&period;0&rpar;

    转义字符 字符串取值没什么限制,在引号""中可以填:数字.中文.字母 .特殊字符.以及他们的组合,字符串的值都要用双引号扩起来,比如 "我是字符型",当然,有人 ...

  7. 在C&num;中internal关键字是什么意思?和protected internal区别

    我来补充一下,对于一些大型的项目,通常由很多个DLL文件组成,引用了这些DLL,就能访问DLL里面的类和类里面的方法.比如,你写了一个记录日志的DLL,任何项目只要引用此DLL就能实现记录日志的功能, ...

  8. Python -- Web -- 使用框架

    Python的web框架有很多: Flask,Django,Zope2,Web.py,Web2py,Pyramid,Bottle, Tornado... Flask 轻量级,比较简单 from fla ...

  9. 某控股公司OA系统ORACLE DG搭建

    *此处安装ORACLE DATAGUARD是利用ORACLE RMAN DUPLICATE方式安装.*可以搭建好ORACLE DG再来impdp生产数据,也可以先导入主库数据再来做DG*注意看下面的配 ...

  10. 性能测试-并发和QPS

    性能测试-并发和QPS 响应时间: cpu计算耗时 + cpu等待耗时 + 网络io耗时 + 磁盘io耗时 并发: 服务端并发和客户端并发不是同一个概念.客户端并发仅仅是为了模拟多用户访问,服务端并发 ...