数据结构Python版--树

一、树

作为数据结构的树和现实世界中的树有很多共同之处,二者皆有根、茎、叶。不同之处在于前者的根在顶部而叶在底部。
树的第一个属性是层次性,第二个属性是一个节点的所有子节点都与另一个节点的所有子节点无关,第三个属性是叶子节点都是独一无二的。
节点是树的基础,我们称作键,节点可以带有附加信息,称为有效载荷。边是树的另一个基础部分,两个节点通过一条边相连,表示它们之间存在的关系,除了根节点以外,每个节点都仅有一条入边,可以有多条出边。根节点是树中唯一没有入边的节点。路径是由边连接的有序节点列表,层数是从根节点到n的唯一路径长度,根节点的层数为0.树的高度是其中节点层数的最大值。
定义1:树由节点及连接节点的边构成,具有以下属性:有一个根节点,除了根节点外,其他的每个节点都与唯一的父节点相连,从根节点到其他每个节点都有且仅有一条路径,如果每个节点有两个子节点,就称这样的树为二叉树。
定义2:一颗树要么为空,要么由一个根结点和零棵或多棵子树欧城,子树本身也是一棵树。每棵子树的根节点通过一条边连到父树的根节点。

实现

BinaryTree()创建一个二叉树实例
getLeftChild()返回当前节点的左子节点所对应的二叉树
getRightChild()返回当前节点的右子节点所对应的二叉树
setRootVal(val)在当前节点中存储参数val中的对象
getRootVal()返回当前节点存储的对象
insertLeft(val)新建一颗二叉树,并将其作为当前节点的左子节点
insertRight(val)新建一颗二叉树,并将其作为当前节点的右子节点
实现树的关键在于选择一个好的内部存储技巧。
在这里插入图片描述

列表之列表

在列表之列表的树中,我们将根节点的值作为列表的第一个元素,第二个元素代表的左子树的列表,第三个元素是代表右子树的列表。可以通过标准的切片来访问子树。
在这里插入图片描述
在这里插入图片描述

'''
不是定义二叉树类
是创建可用于标准列表的函数
'''
def BinaryTree(r):
    return [r,[],[]]

'''
添加左子树,需要在列表的第二个位置加入一个新列表
如果列表的第二个位置已经有内容了,要保留已有内容,并将它作为新列表的左子树
在插入左子树时,先活得当前的左子树所对应的列表,然后加入新的左子树
将旧的左子树作为新节点的左子树
插入右子树也是一样的道理
'''
# 插入左子树
def insertLeft(root,newBranch):
    t = root.pop(1)
    if len(t)>1:
        root.insert(1,[newBranch,t,[]])
    else:
        root.insert(1,[newBranch,[],[]])
    return root

def insertRight(root,newBranch):
    t = root.pop(2)
    if len(t)>1:
        root.insert(2,[newBranch,[],t])
    else:
        root.insert(2,[newBranch,[],[]])

# 访问函数
def getRootVal(root):
    return root[0]

def setRootVal(root,newVal):
    root[0] = newVal

def getLeftChild(root):
    return root[1]

def getRightChild(root):
    return root[2]

r = BinaryTree(3)
insertLeft(r,4)
insertLeft(r,5)
insertRight(r,6)
insertRight(r,7)
print("1",r)

运行结果:
1 [3, [5, [4, [], []], []], [7, [], [6, [], []]]]

节点与引用

利用节点与引用,定义一个类,其中有根节点和左右子树的属性。
在这里插入图片描述
在这里插入图片描述

'''
构造方法接受一个对象,并将其存储到根节点中
正如可以在列表中存储任何对象,根节点对象也可以成为任何对象的引用
'''
class BinaryTree:
    def __init__(self,rootObj):
        self.key = rootObj
        self.leftChild = None
        self.rightChild = None
    '''
    两种情况,一种是根本没有左子节点 
    另一种是已经存在左子节点,插入一个节点,并将已有的左子节点降一层。
    '''
    def insertLeft(self,newNode):
        if self.leftChild == None:
            self.leftChild = BinaryTree(newNode)
        else:
            t = BinaryTree(newNode)
            t.left = self.leftChild
            self.leftChild = t

    def insertRight(self,newNode):
        if self.rightChild == None:
            self.rightChild = BinaryTree(newNode)
        else:
            t = BinaryTree(newNode)
            t.right = self.rightChild
            self.rightChild = t

    # 二叉树访问函数
    def getRight(self):
        return self.rightChild
    def getLeft(self):
        return self.leftChild

    def setRootVal(self,obj):
        self.key = obj
    def getRootVal(self):
        return self.key

# 根节点的左右子节点本身都是BinaryTree类的实例
r = BinaryTree('a')
print("2",r.getRootVal())
print("3",r.getLeft())
r.insertLeft('b')
print("4",r.getLeft())
print("5",r.getLeft().getRootVal())

运行结果:
2 a
3 None
4 <__main__.BinaryTree object at 0x000002A0081CB550>
5 b

二叉树的应用

解析树

解析树可以用来表示现实世界中像句子或数学表达式这样的构造。
在这里插入图片描述
问题:
1.如何根据完全括号表达式构建解析树
2.如何计算解析树中的表达式
3.如何将解析树还原成最初的数学表达式
创建4条规则:
1.如果当前标记是(,就可以为当前节点添加一个左子节点,并下沉至该子节点;2.如果当前标记在列表[‘+’,‘-’,‘/’,'']中就将当前节点的值设为当前标记对应的运算符;为当前接待你添加一个右子节点,并下沉至该子节点;3.如果当前标记是数字,就将当前节点的值设为这个数并返回至父节点;4.如果当前标记是),就跳到当前节点的父节点。
表达式(3+(4
5))构建过程
在这里插入图片描述

# 输出树
    def postorder(self):
        if self.leftChild:
            self.leftChild.postorder()
        if self.rightChild:
            self.rightChild.postorder()
        print(self.key)

def buildParseTree(fpexp):
    #分割标记
    fplist = fpexp.split()
    pStack = Stack()
    # 创建树
    eTree = BinaryTree('')
    pStack.push(eTree)
    currentTree = eTree
    for i in fplist:
        if i == '(':
        # 创建左子树
            currentTree.insertLeft('')
            pStack.push(currentTree)
            currentTree = currentTree.getLeft()
        elif i not in ['+', '-', '*', '/', ')']:
            # 数值
            currentTree.setRootVal(int(i))
            parent = pStack.pop()
            currentTree = parent
        elif i in ['+', '-', '*
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值