☀️上一节我们学习了数据结构里面的各种排序算法,今天,我们接着学习数据结构中又一重要的结构:树,对往期内容感兴趣的小伙伴可以参考下面内容👇:
🌵数据结构中所说的‘树’,一般都是指二叉树,许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。
树结构在我们生活中很常见,我们举一些例子:
生物物种分类树
从树的顶部开始,沿着由椭圆和箭头构成的路径,一直到底部。一个节点的所有子节点都与另一个节点的所有子节点无关,叶子节点都是独一无二。
先介绍树的一些术语:
树的定义有两种:
第一种:
第二种:
一棵树要么为空,要么由一个根节点和零棵或多棵子树构成,子树本身也是一棵树。 每棵子树的根节点通过一条边连到父树的根节点。从树的递归定义可知,图中的树至少有 4 个节点,因为三角形代表的子树必定有一个根节点。这棵树或许有更多 的节点,但必须更深入地查看子树后才能确定。
列表表示方式
树的根节点是 myTree[0],左子树是 myTree[1],右子树是 myTree[2]
表示方法如下:
#树
mytree=['a',['b',['d',[],[]],['e',[],[]]],['c',['f',[],[]],[]]]
#左子树
mytree[1]
#右子树
mytree[2]
创建树的函数
def binarytree(r):#创建一颗以r为根节点的树
return [r,[],[]]
def insertleftree(root,newbr):#向左节点插入一棵树
t=root.pop(1)
if len(t)>1:
root.insert(1,[newbr,t,[]])
else:
root.insert(1,[newbr,[],[]])
return root
def insertrighttree(root,newbr):#向右节点插入一颗树
t=root.pop(2)
if len(t)>1:
root.insert(2,[t,newbr,[]])
else:
root.insert(2,[t,newbr,[]])
return root
def getlefttree(r):#获取左子树
return r[1]
def getrighttree(r):#获取右子树
return r[2]
利用节点与引用。我们将定义一个类,其中有根节点和左右子树的属性。 这种表示法遵循面向对象编程范式,结构如下:
面向对象表示方法
树的实现
class binarytree2:
def __init__(self,key):
self.root=key
self.left=None
self.right=None
def insertleft(self,nbran):#插入左节点
if self.left ==None:
self.left=binarytree2(nbran)
else:
t=binarytree2(nbran)
t.left=self.left
self.left=t
def insertright(self,nbran):#插入右节点
if self.right==None:
self.right=binarytree2(nbran)
else:
t=binarytree2(nbran)
t.right=self.right
self.right=t
def getrighttree(self):#获取右子树
return self.right
def getlefttree(self):#获取左子树
return self.left
def gettreeroot(self):#获取根节点
return self.root
树的实现已经齐全了,现在来看看如何用树解决一些实际问题。这里介绍解析树,可以用它 来表示现实世界中像句子或数学表达式这样的构造。
句子解析树
数学表达式解析树
构建解析树的第一步是将表达式字符串拆分成标记列表。需要考虑 4 种标记:左括号、右括号、运算符和操作数。我们知道,左括号代表新表达式的起点,所以应该创建一棵对应该表达式的新树。反之,遇到右括号则意味着到达该表达式的终点。我们也知道,操作数既是叶子节点,也是其运算符的子节点。此外,每个运算符都有左右子节点。规则如下:
解析树实现方式
rom pythonds.basic import Stack
from pythonds.trees import BinaryTree
def buildParseTree(teststring):#解析树创建
str=teststring.split()#将字符串拆分
pstack=Stack()#创建一个栈,方便访问树节点
etree=BinaryTree('')#创建树
pstack.push(etree) #将树压入栈中
currenttree = etree
for i in str: #依次判断每个字符所属情况
if i == '(':
currenttree.insertLeft('')
pstack.push(currenttree)
currenttree = currenttree.getLeftChild()
elif i in ['+','-','/','*']:#是运算符,创建右节点
currenttree.setRootVal(i)
currenttree.insertRight('')
pstack.push(currenttree)
currenttree=currenttree.getRightChild()
elif i not in ['+','-','/','*',')']:#是数字设置该节点的值
currenttree.setRootVal(eval(i))
currenttree=pstack.pop()
elif i ==')':
currenttree = pstack.pop()
else:
raise ValueError("Unknown Operator: " + i)
return etree
可通过如下调用:
树是创建好了,可是怎么遍历树呢?按节点的访问方式分为 3 种。我们将对所有节点的访问称为“遍历”,共有 3 种遍历方式,分别为前序遍历、中序遍历和后序遍历。
三种遍历方式
#前序遍历
def preorder(tree):
if tree:
print(tree.getRootVal())
preorder(tree.getLeftChild())
preorder(tree.getRightChild())
#中序遍历
def inorder(tree):
if tree != None:
inorder(tree.getLeftChild())
print(tree.getRootVal())
inorder(tree.getRightChild())
#后序遍历
def postorder(tree):
if tree != None:
inorder(tree.getLeftChild())
inorder(tree.getRightChild())
print(tree.getRootVal())
效果如下:
《python数据结构与算法》
《大话数据结构》
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://liuxiaocong.blog.csdn.net/article/details/122240811
内容来源于网络,如有侵权,请联系作者删除!