• python 算法 day8 树


    树的构成要素:

    节点(Node) 边(Edge) 根节点(Root) 路径(Path) 子节点集(Children) 父节点(Parent) 兄弟节点(Sibling)

    子树 (Subtree) 叶节点(Leaf Node) 层数(Level) 高度(height)

    定义一:树有以下特征:

    • 有一个节点是根节点
    • 除了根节点外的每一个节点n,都通过一条边与另一个节点p相连,p是n的父节点
    • 可以沿着唯一的路径从根节点到达每个节点
    • 如果这个树每个节点都至多有两个子节点,我们称它为二叉树

    定义二:

    每个树或者为空或者包含一个根节点和零个或多个子树,其中每个子树也符合这样的定义

    通过嵌套列表来实现树

    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,[],[]]) return root 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]

     第二种实现树的方式 使用节点和引用 利用对象的方式

    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.leftChild = self.leftChild
                self.leftChild=t
        def insertRight(self,newNode):
            if self.rightChild == None:
                self.rightChild = BinaryTree(newNode)
            else:
                t = BinaryTree(newNode)
                t.leftChild = self.leftChild
                self.leftChild = t
        def getRightChild(self):
            return self.rightChild
        def getLeftChild(self):
            return self.leftChild
        def setRootVal(self,obj):
            self.key = obj
        def getRootVal(self):
            return self.key

    在插入时我们必须考虑两种情况,第一种情况:当前没有现有左子节点,当没有左子节点时,简单的将新节点添加到树中即可

    有左子节点时 我们插入节点时 需要把原有的左子节点进行降级 

     解析树

     比如(7+3)*(5-2):如果当前读入字符是‘(’添加一个新的节点作为当前节点的子节点,当前节点下降

    如果当前读入的字符在列表 ['+','-','/','*'] 中,将当前节点的根值设置为当前读入的字符。添加一个新的节点(node)作为当前节点的右子节点,当前节点下降。

    如果当前读入的字符是一个数字,将当前节点的根值设置为该数字,当前节点变为它的父节点
    如果当前读入的字符是 ')' ,当前节点变为其父节点(parent)。

    写一个解析树

    from pythonds.basic.stack import Stack
    from pythonds.trees.binaryTree import BinaryTree
    def buildParseTree(parse):
        fplist = parse.split()  根据空格分割 每个字符串
        pstack = Stack()
        eTree = BinaryTree('')
        pstack.push(eTree)
        currentTree = eTree
        for i in fplist:
            if i == '(':
                currentTree.insertLeft('')
                pstack.push(currentTree)
                currentTree = currentTree.getLeftChild()
            elif i not in ['+','-','*','/',')']:
                currentTree.setRootVal(int(i))
                parent = pstack.pop()
                currentTree = parent
            elif i in ['+','-','*','/']:
                currentTree.setRootVal(i)
                currentTree.insertRight('')
                pstack.push(currentTree)
                currentTree = currentTree.getRightChild()
            elif i == ')':
                currentTree = pstack.pop()
            else:
                raise ValueError
        return eTree
    pt  = buildParseTree("( ( 1 + 2 ) * 3 )")
    pt.postorder()

     使用堆栈保持对父节点的跟踪,当我们要下降到当前节点的子节点时,我们先将当前节点压入栈中,而当我们想要返回当前节点的父节点时,我们就从堆栈中弹出该父节点

    在解析树中,叶节点总是操作数 我们只需检查一个操作符是否是叶节点,递归调用使我们有效的向叶节点移动

    
    
    import operator

    def evaluate(parseTree): opers
    = {'+':operator.add,'-':operator.sub,'*':operator.mul,'/':operator.truediv} leftc = parseTree.getLeftChild() rightc = parseTree.getRightChild() if leftc and rightc: fn = opers[parseTree.getRootVal()] return fn(evaluate(leftc),evaluate(rightc)) else: return parseTree.getRootVal() print(evaluate(pt))

     树的遍历

    • 前序遍历 :在前序遍历中,我们先访问根节点,然后递归地前序遍历访问左子树,再递归地前序遍历访问右子树
    • 中序遍历:先访问左子树 再根节点 最后右子树
    • 后序遍历:先访问左子树和右子树 ,最后访问根节点

     

    从头到尾阅读这本书   前序遍历正好符合这种规则

    前序遍历
    def preordder(tree):
    if tree: print(tree.getRootVal()) preordder(tree.getLeftChild()) preordder(tree.getRightChild()) 后序遍历 def postorder(tree): if tree: postorder(tree.getLeftChild()) postorder(tree.getRightChild()) print(tree.getRootVal()) 中序遍历 def inorder(tree): if tree: inorder(tree.getLeftChild()) print(tree.getRootVal()) inorder(tree.getRightChild())

     用遍历来计算解析树

    def evaluate(parseTree):
        opers = {'+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.truediv}
        if parseTree:
            leftc = postorder(parseTree.getLeftChild())
            rightc = postorder(parseTree.getRightChild())
    
            if leftc and rightc:
                return opers[parseTree.getRootVal()](leftc,rightc)
    
            else:
                return parseTree.getRootVal()
  • 相关阅读:
    echarts x轴文字显示不全(xAxis文字倾斜比较全面的3种做法值得推荐)
    从输入URL到页面加载的过程?由一道题完善自己的前端知识体系!
    浏览器多进程架构、浏览器内核多线程、js单线程、GUI 渲染线程 与 JavaScript引擎线程互斥 原理
    通过script src引入ElementUI时,使用语句:window.ELEMENT.MessageBox.alert(xxx) 调用弹出框
    计算2个日期之间的天数
    js 字符串转对象
    requestAnimationFrame 知识点
    vue项目权限控制
    css中权重与继承
    Flex Basis与Width的区别
  • 原文地址:https://www.cnblogs.com/suizhixxie/p/10424644.html
Copyright © 2020-2023  润新知