[超水笔记之五]北大慕课:数据结构与算法Python版

树:“非线性”数据结构

树结构相关术语

  • 节点Node: 组成树的基本部分

  • 边Edge: 组成树的另一个基本结构

  • 子节点Childre : 入边均来自同一个节点的若干节点

  • 父节点Parent : 一个节点是其所有出边所连接节点的父节点

  • 兄弟节点Sibling : 具有同一个父节点的节点之间称为兄弟节点

  • 子树Subtree : 一个节点和其所有子孙节点,以及相关边的集合

  • 叶节点Leaf : 没有子节点的节点称为叶节点

  • 层级Level : 从根节点开始到达一个节点的路径,所包含的边的数量,
    称为这个节点的层级

  • 高度 : 树中所有节点的最大层级称为树的高度

树的定义1

树由若干节点,以及两两连接节点的边组成,并有如下性质:

  1. 其中一个节点被设定为根

  2. 每个节点n(除根结点),都恰链接一条来自节点P的边,P是n的父节点

  3. 每个节点从根开始的路径是唯一的,如果每个节点最多有两个子节点,称为“二叉树”

树的定义2(递归定义)

树是:

空集,或是由根节点及0或多个子树构成(其中子树也是树),
每个子树的根到根节点具有边相连。
树递归定义

实现树:嵌套列表法

嵌套列表

  • 嵌套列表法代码:
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.rightChild = self.rightChild
            self.rightChild = 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 buildParseTree(fpexp):
    fplist = fpexe.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("")
            pStack.push(currentTree)
            currentTree = currentTree.getRightChild()
        elif i == ")":
            currentTree = pStack.pop()
        else:
            raise ValueError
    return eTree
  • 代码:表达式解析树求值
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()

树的遍历Tree Traversals

  • 三种遍历
  1. 前序遍历(preorder):先访问根节点,
    再递归地前序访问左子树、最后前序访问右子树
  2. 中序遍历(inorder):先递归地中序访问左子树,
    在访问根节点,最后中序访问右子树
  3. 后序遍历(postorder):先递归的后序访问左子树,在后序访问右子树,
    最后访问根节点
  • 递归算法代码
def preorder(tree):
    if tree:
        print(tree.getRootVal())
        preorder(tree.getLeftChild())
        preorder(tree.getRightChild())

def postorder(tree):
    if tree != None:
        postorder(tree.getLeftChild())
        preorder(tree.getRightChild())
        print(tree.getRootVal())

def inorder(tree):
    if tree != None:
        inorder(tree.getLeftChild())
        print(tree.getRootVal())
        inorder(tree.getRightChild())
  • 亦可:
def postordereval(tree):
    opers = {"+":operator.add,"-":operator.sub,
             "*":operator.mul,"/":operator.truediv}
    
    res1 = None
    res2 = None
    
    if tree:
        res1 = postordereval(tree.getLeftChild())
        res2 = postordereval(tree.getRightChild())
        
        if res1 and res2:
            return opers[tree.getRootVal()](res1,res2)
        else:
            return tree.getRootVal()

二叉堆Binary Heap

  • 操作定义:
  1. BinaryHeap() 创建一个空二叉堆对象
  2. insert(k) 将新key加入到堆
  3. findMin() 返回堆中最小项,最小项仍保留在堆中
  4. delMin() 返回堆中最小项,同时删除
  5. isEmpty() 返回堆是否为空
  6. size() 返回堆中key个数
  7. buildHeap(list) 从一个key列表创建新堆
  • 代码:
class BinHeap(object):
    def __init__(self):
        self.heapList = [0]
        self.currentSize = 0
        
    def percUP(self,i):
        while i //2 >0:
            if self.heapList[i] <self.heapList[i//2]:
                tmp = self.heapList[i//2]
                self.heapList[i//2] = self.heapList[i]
                self.heapList[i] = tmp
            i = i //2
            
    def insert(self,k):
        self.heapList.append(k)
        self.currentSize = self.currentSize + 1
        self.percUP(self.currentSize)

    def percDown(self,i):
        while  (i*2) <= self.currentSize:
            mc = self.minChild(i)
            if self.heapList[i] > self.heapList[mc]:
                tmp = self.heapList[i]
                self.heapList[i] = self.heapList[mc]
                self.heapList[mc] = tmp
            i = mc

    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 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
    
    # buildheap:从无序表生成堆
    def buildHeap(self,alist):
        i = len(alist)//2
        self.currentSize = len(alist)
        self.heapList = [0] +alist[:]
        print(len(self.heapList),i)
        while i>0:
            print(self.heapList,i)
            self.percDown(i)
            i -= 1
        print(self.heapList,i)

二叉查找树

  • ADT Map操作:
  1. map() 创建空映射
  2. put(key,val) 将key-val关联加入映射中,若key已存在,则val替换旧值
  3. get(key) 给定key,返回关联数据值,若不存在,返回none
  4. del: 通过del map[key] 删除key-val关联
  5. len() 返回key-val关联的数目
  6. in 通过key in map形式,返回key是否存在于关联中,bool型
  • 二叉查找树BST性质:

    比父节点小的key都出现在左子树,比父节点大的key都出现在右子树

  • 二叉查找树BST性质:

class BinarySearchTree(object):
    def __init__(self):
        self.root = None
        self.size = 0

    def length(self):
        return self.size

    def __len__(self):
        return self.size

    def __iter__(self):
        return self.root.__iter__()

class TreeNode(object):
    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

平衡二叉查找树:AVL树定义

  • AVL树实现中,需要对每个节点跟踪“平衡因子balance factor”参数

  • 平衡因子是根据节点的左右子树的高度来定义的,确切的说,
    是左右子树的高度差
    平衡二叉树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值