二叉树的右视图 python_Python 实现二叉树,并可视化

二叉树选自百度百科,如有错误,欢迎指正

二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”和“右子树”。二叉树常被用于实现二叉查找树和二叉堆。

二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。每个子树都满足,大于它的左子树及其所有子节点,小于它的右子树及其所有子节点

代码

首先需要先定义节点类

class Node:

def __init__(self, value, left=None, right=None):

self.value = value # 节点的值

self.left = left # 左子节点

self.right = right # 右子节点

接下来定义树类

from collections import Iterable

class BinaryTree:

def __init__(self, seq=()):

assert isinstance(seq, Iterable) # 确保输入的参数为可迭代对象

self.root = None

这样,BinaryTree 的初始化就完成了

可是 BinaryTree 还没有任何数据,参数 seq 也没有被使用,这时候我们需要实现 insert 方法来插入数据

插入

因为 BinaryTree 的每个节点都是节点对象,所以需要先生成 Node 实例。默认第一个节点为根节点

def __init__(self, seq=()):

assert isinstance(seq, Iterable)

self.root = None

self.insert(*seq)

def insert(self, *args):

if not args:

return

if not self.root:

self.root = Node(args[0])

args = args[1:]

for i in args:

seed = self.root

while True:

if i > seed.value:

if not seed.right:

node = Node(i)

seed.right = node

break

else:

seed = seed.right

else:

if not seed.left:

node = Node(i)

seed.left = node

break

else:

seed=seed.left

最小值、最大值

def minNode(self):

node = self.root

while node.left:

node = node.left

return node

def maxNode(self):

node = self.root

while node.right:

node = node.right

return node

查找

通过给定值,返回对应的节点对象,如果没有则返回 None

def find(self, item):

node = self.root

while node:

if item > node.value:

node = node.right

elif item < node.value:

node = node.left

else:

return node

删除

二叉树删除操作有点复杂。被删除节点没有子节点

被删除节点有一个子节点

被删除节点有两个子节点

为方便描述,简称被删除节点为 A

前两种比较简单,第一种只需要将 A 的父节点对应属性改为 None。第二种,需要将 A 的父节点与子节点关联。第三种就相对复杂一点,有两种方案,寻找 A 的右子树的最小值或左子树的最大值节点 B,根据 B 节点创建临时节点,删除节点 B,然后用临时节点替换 A 节点这里使用第一种方式,使用右子树最小值节点

在此之前,我们需要改写一下 find、minNode 和 maxNode 方法,使其返回更多数据,便于删除操作

def find(self, item, seed=None):

node = seed or self.root # 修改查询起点

parent = None # 父节点

while node:

if item > node.value:

parent, node = node, node.right

elif item < node.value:

parent, node = node, node.left

else:

return (node, parent)

def minNode(self, seed=None):

node = seed or self.root

while node.left:

node = node.left

return node

def maxNode(self, seed=None):

node = seed or self.root

while node.right:

node = node.right

return node

接下来是 remove 方法

def remove(self, item):

result = self.find(item)

if result:

new_node = None # 替换 A 的节点

del_node, del_node_parent = result

if del_node.value == self.root.value:

raise ValueError('can not remove root') # 根节点固定

if del_node.left and del_node.right:

right_min = self.minNode(seed=del_node.right)

new_node = Node(right_min.value)

# 当 A 节点的右子树节点没有子节点时,临时节点的右子节点 为 None

if del_node.right.value == new_node.value:

new_node.left = del_node.left

else:

new_node.left, new_node.right = del_node.left, del_node.right

self.remove(right_min.value)

# A 节点的父节点与临时节点关联

elif del_node.left or del_node.right:

new_node = del_node.left or del_node.right

if del_node_parent.left and del_node_parent.left.value == del_node.value:

del_node_parent.left = new_node

elif del_node_parent.right and del_node_parent.right.value == del_node.value:

del_node_parent.right = new_node

del del_node

return

raise ValueError('item not in tree')

可视化

在画图前,需要遍历每一个节点,并为每个节点定义坐标,并连接相邻的节点,这里需要用到 networkx 跟 matplotlib

import networkx as nx

import matplotlib.pyplot as plt

def create_graph(G, node, pos={}, x=0, y=0, layer=1):

pos[node.value] = (x, y)

if node.left:

G.add_edge(node.value, node.left.value)

l_x, l_y = x - 1 / 2 ** layer, y - 1

l_layer = layer + 1

create_graph(G, node.left, x=l_x, y=l_y, pos=pos, layer=l_layer)

if node.right:

G.add_edge(node.value, node.right.value)

r_x, r_y = x + 1 / 2 ** layer, y - 1

r_layer = layer + 1

create_graph(G, node.right, x=r_x, y=r_y, pos=pos, layer=r_layer)

return (G, pos)

def draw(node): # 以某个节点为根画图

graph = nx.DiGraph()

graph, pos = create_graph(graph, node)

fig, ax = plt.subplots(figsize=(8, 10)) # 比例可以根据树的深度适当调节

nx.draw_networkx(graph, pos, ax=ax, node_size=300)

plt.show()

效果图如下:

这样就可以将抽象的树结构画出来,图像美化可以查看对应的文档调整

文章内容如有错漏,欢迎指正

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值