1. 树的概念

树是一种非线性的层次型数据结构,不像数组、链表是一条直线,而是一层一层往下分叉,像现实中的倒着长的树。

2. 树的基本话术

(1)根节点:树最顶部唯一的节点,没有父节点

(2)父 / 子节点:上层是父,下层分叉出来的是子

(3)叶子节点:没有子节点的末端节点

(4)层次:根是第 1 层,往下层数递增

(5)高度:层级的最大值

3. 树的实现

3.1 树的嵌套列表实现

def binary_tree(r):
    # 创建根节点
    return [r,[],[]]  # 二维数组表示树
def insert_left(root,new_branch):
    # 插入左子树
    t= root.pop(1)
    if len(t) > 1:
        root.insert(1,[new_branch,t,[]])
    else:
        root.insert(1,[new_branch,[],[]])
    return root
def insert_right(root,new_branch):
    # 插入右子树
    t = root.pop(2)
    if len(t) > 1:
        root.insert(2,[new_branch,[],t])
    else:
        root.insert(2,[new_branch,[],[]])
    return root
def get_root_val(root):
    # 查看根节点
    return root[0]
def set_root_val(root,new_val):
    # 设置根节点参数
    root[0] = new_val
def get_left_child(root):
    # 查看左子树
    return root[1]
def get_right_child(root):
    # 查看右子树
    return root[2]

3.2 树的链式表达

class Binarytree:
    def __init__(self,root_obj):
        self.key = root_obj
        self.left_child = None
        self.right_child = None
    def insert_left(self,new_node):
        if self.left_child == None:
            self.left_child = Binarytree(new_node)
        else:
            t = Binarytree(new_node)
            t.left_child = self.left_child
            self.left_child = t
    def insert_right(self,new_node):
        if self.right_child == None:
            self.right_child = Binarytree(new_node)
        else:
            t = Binarytree(new_node)
            t.right_child = self.right_child
            self.right_child = t
    def get_right_child(self):
        return self.right_child
    def get_left_child(self):
        return self.left_child
    def set_root_val(self,obj):
        self.key = obj
    def get_root_val(self):
        return self.key

4. 树的遍历

4.1 前序遍历

顺序:根节点→左子树→右子树

def pre_order(tree):
    # 前序遍历
    if tree:
        print(tree.get_root_val())
        pre_order(tree.get_left_child())
        pre_order(tree.get_right_child())

4.2 中序遍历

顺序:左子树→根节点→右子树

def in_order(tree):
    # 中序遍历
    if tree != None:
        in_order(tree.get_left_child())
        print(tree.get_root_val())
        in_order(tree.get_right_child())

4.3 后序遍历

顺序:左子树→右子树→根节点

def post_order(tree):
    # 后序遍历
    if tree != None:
        post_order(tree.get_left_child())
        post_order(tree.get_right_child())
        print(tree.get_root_val())

5. 树的应用

5.1 全括号表达式解析

任务:

(1)从全括号表达式构建表达式解析树

(2)利用表达式解析式对表达式求值

(3)从表达式解析树恢复原表达式的字符串形式

思路:

(1)遇到左括号则创建左子树用于存储数据,并将指针指向左子树(指针下沉)

(2)整个操作过程遵循后进先出原则,创建栈用来保存指针位置,确保操作顺序正确不遗漏

(3)遇到数值则设置当前指针位置节点的值,并将指针上移

(4)遇到右括号则只执行剔除栈中的指针位置的操作

代码如下:

def build_parse_tree(fpexp):
    # 全括号表达式
    fplist = fpexp.split()  # 分隔全括号表达式,返回列表
    pStack = Stack()
    eTree = Binarytree('')  # 创建根节点
    pStack.push(eTree)  # 存入栈底最后最运算
    currentTree = eTree  # 当前节点
    for i in fplist:
        if i == '(':
            currentTree.insert_left('')  # 创建左子树
            pStack.push(currentTree)  # 记录当前节点位置
            currentTree = currentTree.get_left_child()  # 将当前节点指向左子树
        elif i not in ['+','-','*','/',')']:
            # 遍历到操作数时
            currentTree.set_root_val(int(i))  # 设置当前节点的操作数
            parent = pStack.pop()
            currentTree = parent  # 当前节点返回上一个节点
        elif i in ['+','-','*','/']:
            # 遍历到操作符时
            currentTree.set_root_val(i)  # 设置当前节点的操作符
            currentTree.insert_right('')  # 创建右子树
            pStack.push(currentTree)  # 记录当前节点位置
            currentTree = currentTree.get_right_child()  # 将当前节点下沉到右子树
        elif i == ')':
            # 消除栈中的节点位置,一轮全括号解析结束
            currentTree = pStack.pop()
        else:
            raise ValueError
    return eTree

5.2 递归求值函数

递归原则:

(1)基本结束条件:

叶节点为最简单的子树,没有左右子节点,其根节点的数据项即为子表达式树的值。

(2)缩小规模:

将表达式树分为左子树、右子树。

(3)调用自身:

分别调用evaluate函数计算左子树和右子树的值,然后将左右子树的值依根节点的操作符进行计算,从而得到表达式的值。

import operator
def evaluate(parse_tree):
    # 递归解析法
    opers = {'+':operator.add,
             '-':operator.sub,
             '*':operator.mul,
             '/':operator.truediv,}
    leftC = parse_tree.get_left_child()
    rightC = parse_tree.get_right_child()
    if leftC and rightC:
        fn = opers[parse_tree.get_root_val()]
        return fn(evaluate(leftC),evaluate(rightC))
    else:
        return parse_tree.get_root_val()

更多推荐