美文网首页
数据结构与算法复习(二)

数据结构与算法复习(二)

作者: 北冢 | 来源:发表于2018-03-16 16:05 被阅读0次

    1.4 树(Tree)

    1.4.1 术语

    节点、边、根、路径、子节点、父节点、兄弟、子树、叶节点、层数、高度

    1.4.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
        
        def preorder(self):
            
            print(self.key)
            if self.leftChild:
                self.leftChild.preorder()
            if self.rightChild:
                self.rightChild.preorder()
    
    r = BinaryTree('a')
    print(r.getRootVal())
    print(r.getLeftChild())
    
    a
    None
    
    r.insertLeft('b')
    print(r.getLeftChild())
    
    <__main__.BinaryTree object at 0x1111f8518>
    

    1.4.3 分析树

    分析树(parse tree),也叫具体语法树(concrete syntax tree),不同于抽象语法树。

    使用表达式:(3+(4*5)),构建分析树。

    规则如下:

    • 如果当前符号是 '(' ,添加一个新节点作为当前节点的左子节点,并下降到左子节点(currentTree)。

    • 如果当前符号在列表 ['+', '-', '/', '*'] 中,请将当前节点的根植设置为当前符号表示的运算符。添加一个新节点作为当前节点的右子节点。

    • 如果当前符号是数字,请将当前节点的根值设置为该数字并返回到父节点。

    • 如果当前符号是 ')',则转到当前节点的父节点。

    from pythonds.basic.stack import Stack
    from pythonds.trees.binaryTree import BinaryTree
    
    def preorder(tree):
        if tree:
            print(tree.getRootVal())
            preorder(tree.getLeftChild())
            preorder(tree.getRightChild())
    
    
    def buildParseTree(fpexp):
        fplist = fpexp.split()
        pStack = Stack()
        eTree = BinaryTree('')
        pStack.push(eTree)
        currentTree = eTree
        
        for i in fplist:
            if i == '(':
                # 规则 1
                currentTree.insertLeft('')
                pStack.push(currentTree)
                currentTree = currentTree.getLeftChild()
            elif i not in ['+', '-', '/', '*']:
                # 规则 3
                currentTree.setRootVal(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
        currentTree.preorder()
                
    
    pt = buildParseTree('((10+5)*3)')
    
    ((10+5)*3)
    

    1.4.4 树的遍历

    前序遍历:根节点 -> 左子树 -> 右子树
    中序遍历:左子树 -> 根节点 -> 右子树
    后序遍历:左子树 -> 右子树 -> 根节点

    后序遍历的常见用法,即计算分析树。

    1.4.5 基于二叉堆的优先队列

    1.4.5.1 二叉堆结构

    class BinHeap:
        def __init__(self):
            self.heapList = []
            self.currentSize = 0
        def percUp(self, i): # i 为末尾
            while i//2 > 0: #  不是头节点
                if self.heapList[i] < self.heapList[i//2]:
                      self.heapList[i], self.heapList[i//2] = self.heapList[i//2], self.headpList[i]
                i = i//2
        def insert(self, k):
            self.heapList.append(k)
            self.currentSize = self.currentSize + 1
            self.percUp(self.currentSize)
        def minChild(self, i):
            # 给出最小节点
            if i * 2 + 1 > self.currentSize:
                return i * 2
            else:
                if self.heapList[i*2] < self.heapList[i*2+1]:
                    return i * 2
                else:
                    return i * 2 + 1
        def percDown(self, i):
            while ( i * 2 ) <= self.currentSize:
                mc = self.minChild(i)
                if self.heapList[i] > self.heapList[mc]:
                    self.heapList[i], self.heapList[mc] = self.heapList[mc] + self.heapList[i]
                i = mc
        def delMin(self):
            retval = self.heapList[1]
            self.heapList[1] = self.heapList[self.currentSize]
            self.currentSize = self.currentSize - 1
            self.heapList.pop()
            self.percDown(1)
            return retval
        def bulidHeap(self, alist):
            i = len(alist) // 2
            self.currentSize = len(alist)
            self.heapList = [0] + alist[:]
            while (i > 0):
                self.percDown(i)
                i = i - 1
    

    1.4.6 二叉查找树

    BST属性:左子树的 key 小于父节点,右子树的 key 都大于父节点。

    class TreeNode:
        def __init__(self,key,val,left=None,right=None,parent=None):
            self.key = key
            self.payload = val
            self.leftChild = left
            self.rightChild = right
            self.parent = parent
    
        def hasLeftChild(self):
            return self.leftChild
    
        def hasRightChild(self):
            return self.rightChild
    
        def isLeftChild(self):
            return self.parent and self.parent.leftChild == self
    
        def isRightChild(self):
            return self.parent and self.parent.rightChild == self
    
        def isRoot(self):
            return not self.parent
    
        def isLeaf(self):
            return not (self.rightChild or self.leftChild)
    
        def hasAnyChildren(self):
            return self.rightChild or self.leftChild
    
        def hasBothChildren(self):
            return self.rightChild and self.leftChild
    
        def replaceNodeData(self,key,value,lc,rc):
            self.key = key
            self.payload = value
            self.leftChild = lc
            self.rightChild = rc
            if self.hasLeftChild():
                self.leftChild.parent = self
            if self.hasRightChild():
                self.rightChild.parent = self
    
    
    class BinarySearchTree:
    
        def __init__(self):
            self.root = None
            self.size = 0
    
        def length(self):
            return self.size
    
        def __len__(self):
            return self.size
    
        def put(self,key,val):
            # 插入新节点
            if self.root:
                self._put(key,val,self.root)
            else:
                self.root = TreeNode(key,val)
            self.size = self.size + 1
    
        def _put(self,key,val,currentNode):
            if key < currentNode.key:
                if currentNode.hasLeftChild():
                       self._put(key,val,currentNode.leftChild)
                else:
                       currentNode.leftChild = TreeNode(key,val,parent=currentNode)
            else:
                if currentNode.hasRightChild():
                       self._put(key,val,currentNode.rightChild)
                else:
                       currentNode.rightChild = TreeNode(key,val,parent=currentNode)
    
        def __setitem__(self,k,v):
            return self.put(k,v)
    
        def get(self,key):
            if self.root:
                res = self._get(key,self.root)
                if res:
                    return res.payload
                else:
                    return None
    
        def _get(self,key,currentNode):
            if not currentNode:
                return None
            elif currentNode.key == key:
                return currentNode
            elif key < currentNode.key:
                return self._get(key,currentNode.leftChild)
            else:
                return self._get(key,currentNode.rightChild)
    
        def __getitem__(self,key):
            return self.get(key)
    
        def __contains__(self,key):
            if self._get(key,self.root):
                return True
            else:
                return False
    
        def delete(self,key):
            if self.size > 1:
                nodeToRemove = self._get(key,self.root)
            if nodeToRemove:
                self.remove(nodeToRemove)
                self.size = self.size-1
            else:
                 raise KeyError('Error, key not in tree')
            if self.size == 1 and self.root.key == key:
                self.root = None
                self.size = self.size - 1
            else:
                raise KeyError('Error, key not in tree')
    
        def __delitem__(self,key):
            return self.delete(key)
    
        def spliceOut(self):
            if self.isLeaf():
                if self.isLeftChild():
                     self.parent.leftChild = None
                else:
                     self.parent.rightChild = None
            elif self.hasAnyChildren():
                if self.hasLeftChild():
                    if self.isLeftChild():
                        self.parent.leftChild = self.leftChild
                    else:
                        self.parent.rightChild = self.leftChild
                        self.leftChild.parent = self.parent
                else:
                    if self.isLeftChild():
                         self.parent.leftChild = self.rightChild
                    else:
                        self.parent.rightChild = self.rightChild
                        self.rightChild.parent = self.parent
    
        def findSuccessor(self):
            succ = None
            if self.hasRightChild():
                succ = self.rightChild.findMin()
            else:
                if self.parent:
                    if self.isLeftChild():
                         succ = self.parent
                    else:
                        self.parent.rightChild = None
                        succ = self.parent.findSuccessor()
                        self.parent.rightChild = self
            return succ
    
        def findMin(self):
            current = self
            while current.hasLeftChild():
                current = current.leftChild
            return current
    
        def remove(self, currentNode):
            if currentNode.isLeaf(): #leaf
                if currentNode == currentNode.parent.leftChild:
                    currentNode.parent.leftChild = None
                else:
                    currentNode.parent.rightChild = None
            elif currentNode.hasBothChildren(): #interior
                succ = currentNode.findSuccessor()
                succ.spliceOut()
                currentNode.key = succ.key
                currentNode.payload = succ.payload
    
            else: # this node has one child
                if currentNode.hasLeftChild():
                    if currentNode.isLeftChild():
                        currentNode.leftChild.parent = currentNode.parent
                        currentNode.parent.leftChild = currentNode.leftChild
                    elif currentNode.isRightChild():
                        currentNode.leftChild.parent = currentNode.parent
                        currentNode.parent.rightChild = currentNode.leftChild
                    else:
                        currentNode.replaceNodeData(currentNode.leftChild.key,
                                                currentNode.leftChild.payload,
                                                currentNode.leftChild.leftChild,
                                                currentNode.leftChild.rightChild)
                else:
                    if currentNode.isLeftChild():
                        currentNode.rightChild.parent = currentNode.parent
                        currentNode.parent.leftChild = currentNode.rightChild
                    elif currentNode.isRightChild():
                        currentNode.rightChild.parent = currentNode.parent
                        currentNode.parent.rightChild = currentNode.rightChild
                    else:
                        currentNode.replaceNodeData(currentNode.rightChild.key,
                                                    currentNode.rightChild.payload,
                                                    currentNode.rightChild.leftChild,
                                                    currentNode.rightChild.rightChild)
    
    

    1.4.7 二叉查找树分析

    如果按照随机顺序添加键,树的高度将在 log2^n,n 为树种的节点树。二叉查找树的最差情况是 O(n)。

    1.4.8 平衡二叉搜索树 ( AVL树 )

    1.4.9 一些概念

    平衡二叉搜索树,又叫 AVL 树,能够自动确保树的平衡,从而保持性能稳定在 O(logN)。
    平衡因子,定义为左子树高度和右子树的高度差。如果平衡因子大于零,子树是左重的。如果平衡因子小于零,子树是右重的。如果平衡因子等于零,那么树就是完美平衡的。
    如果平衡因子是`-1`、`0`或者`1`,那么树称之为平衡。
    

    1.4.10 代码实现

    class AVLTree(BinarySearchTree):
        def _put(self, key, val, currentNode):
            if key < currentNode.key:
                if currentNode.hasLeftChild():
                    self._put(key, val, currentNode.LeftChild)
                else:
                    currentNode.leftChild = TreeNode(key, val, parent=currentNode)
                    self.updateBalance(currentNode.leftChild)
            else:
                if currentNode.hasRightChild():
                    self._put(key, val, currentNode.rightChild)
                else:
                    currentNode.rightChild = TreeNode(key, val, parent=currentNode)
                    self.updateBalance(currentNode.rightChild) 
                    
        def updateBalance(self, node):
            if node.balanceFactor > 1 or node.balanceFactor < -1:
                self.rebalance(node)
                return 
            if node.parent != None:
                if node.isLeftChild():
                    node.parent.balanceFactor += 1
                elif node.isRightChild():
                    node.parent.balanceFactor -= 1
            if node.parent.balanceFactor != 0:
                self.updateBalance(node.parent)
                
            
        def rotateLeft(self, rotRoot):
            pass
        
        def rotateRight(self, rotRoot):
            pass
    

    相关文章

      网友评论

          本文标题:数据结构与算法复习(二)

          本文链接:https://www.haomeiwen.com/subject/edhrqftx.html