Python数据结构与算法分析课后习题(第二版) 第六章 课后练习

目录:

1.扩展buildParseTree方法,使其能够处理字符间没有空格的数字表达式。
2.修改buildParseTree和evaluate,使它们支持逻辑运算符(and、or、not)。注意,not是一元运算符,这会让代码有点复杂。
3.使用findSuccessor方法,写一个非递归的二叉搜索树中序遍历方法。
4.修改二叉搜索树的实现代码,从而实现线索二叉搜索树。为线索二叉搜索树写一个非递归的中序遍历方法。线索二叉搜索树为其中的每个节点都维护者指向后继节点的引用。
5.修改二叉搜索树的实现代码,以正确处理重复的键。也就是说,如果键已在树中,就替换有效载荷,而不是用同一个键插入一个新节点。
6.创建限定大小的二叉堆。也就是说,堆只保持n个最重要的元素。如果堆的大小超过了n,就会舍弃最不重要的元素。
7.整理printexp函数,去掉数字周围多余的括号。
8.使用buildHeap方法,针对列表写一个时间复杂度为O ( l o g n ) O(logn)O(logn)的排序函数。
9.写一个函数,以数学表达式解析树为参数,计算各变量的导数。
10.将二叉树实现为最大堆。
11.使用BinaryHeap类。实现一个叫做PriorityQueue的新类。为PriorityQueue类实现构造方法,以及enqueue方法和dequeue方法。
12.实现AVL树的delete方法。
 


1.扩展buildParseTree方法,使其能够处理字符间没有空格的数字表达式。
2.修改buildParseTree和evaluate,使它们支持逻辑运算符(and、or、not)。注意,       not是一元运算符,这会让代码有点复杂。

"""1.扩展buildParseTree方法,使其能够处理字符间没有空格的数字表达式
   2.修改buildParseTree和evaluate,使它们支持逻辑运算符(and、or、not)。注意,not是一元运算符"""

import operator  # 操作符模块
# 自定义栈类
class Stack(object):
    def __init__(self):  # 初始化空栈
        self.items = []

    def isEmpty(self):  # 是否为空
        return self.items == []

    def push(self, item):  # 入栈
        self.items.append(item)

    def pop(self):  # 出栈
        return self.items.pop()

    def peek(self):  # 查看栈顶元素
        return self.items[len(self.items)-1]

    def size(self):  # 查看栈的大小
        return len(self.items)

# 自定义二叉树类
class BinaryTree(object):
	# 初始化二叉树
	def __init__(self, rootObj):
		self.root = 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.root = obj

	# 获取根节点值
	def getRootVal(self):
		return self.root

# 解析树生成函数
def buildParseTree2(fpexp):  # (传入的完全括号表达式)
    fplist1 = fpexp.split()  # 将传入的完全括号表达式以空格分割成list
    fplist = []  # 
    for i in fplist1:  # 遍历表达式
        if i in ['and', 'not', 'or']:  # 如果遍历到
            fplist.append(i)  # 添加到列表
        elif i == '(not':  # 如果遍历到'(not'
            fplist.append('not')  # 就只添加'not'
        else:
            for j in i:
                if j == 'n':
                    fplist.append('not')
                    break
                else:
                    fplist.append(j)

    pStack = Stack()  # 实例化栈类
    eTree = BinaryTree('')  # 实例化二叉树类,必须有''
    pStack.push(eTree)  # 将空二叉树的根节点(空)入栈
    currentTree = eTree  # 将空二叉树的根节点(空)作为当前节点
    currentTree.setRootVal(eval(fpexp))
    for i in fplist:  # 循环处理表达式list元素
        if i == '(':  # 遇到"(",则
            currentTree.insertLeft('')  # 创建当前节点的空左子节点
            pStack.push(currentTree)  # 将当前节点入栈
            currentTree = currentTree.getLeftChild()  # 将该左子节点作为当前节点
        elif i not in '+-*/)' and i not in ['and', 'or', 'not']:  # 遇到操作数,则
            currentTree.setRootVal(eval(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()  # 将出栈节点(父节点)作为当前节点
        elif i in ['and', 'or', 'not']:  # 遇到逻辑运算符,则
            currentTree.setRootVal(i)  # 将操作符设为当前节点的根植
            currentTree.insertRight('')  # 创建当前节点的空右子节点
            pStack.push(currentTree)  # 将当前节点入栈
            currentTree = currentTree.getRightChild()  # 将该右子节点作为当前节点
        else:
            raise ValueError('Unknown Operator:' + i)  # 抛出异常

    return eTree

# 求值函数,parseTree为当前整个解析树的根节点
def evaluate(parseTree):
    # opers字典是操作符与其对应的运算函数的集合
    opers = {'+': operator.add, '-': operator.sub, '*': operator.mul,
             '/': operator.truediv, 'and': fn_and, 'or': fn_or,
             'not': fn_not}

    leftC = parseTree.getLeftChild()  # 获取解析树根节点的左子树
    rightC = parseTree.getRightChild()  # 获取解析树根节点的右子树
    if parseTree.getRootVal() == 'not':  # 如果根节点的值==not
        fn = opers[parseTree.getRootVal()]  # 获取解析树根节点值对应的opers字典值作为运算函数
        return fn(rightC)  # 将递归获取的左右子树值运算后返回
    else:  # 若当前节点不存在左右子树,说明该节点是叶节点,则
        if leftC and rightC:
            fn = opers[parseTree.getRootVal()]
            return fn(evaluate(leftC), evaluate(rightC))
        else:
            return parseTree.getRootVal()


def fn_and(left, right):
    return left and right


def fn_or(left, right):
    return left or right


def fn_not(right):
    return not right


if __name__ == '__main__':
    tree = buildParseTree2('((1+0) or (not 0))')
    #tree = buildParseTree2(" ( ( ( 3 + 6 ) * ( 7 - 5 ) ) + 4 )")
    print(evaluate(tree))


3.使用findSuccessor方法,写一个非递归的二叉搜索树中序遍历方法。

"""3.使用findSuccessor方法,写一个非递归的二叉搜索树中序遍历方法。"""

class BinarySearchTree:
    def __init__(self):
        self.root = None  # 根节点为空
        self.size = 0  # 节点长度为0

    def length(self):  # 返回长度
        return self.size

    def __len__(self):  # 魔法方法返回长度
        return self.size

    def __iter__(self):  # 实现for循环
        return self.root.__iter__()


    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  # 节点长度+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, key, value):  # 像字典一样输入
        self.put(key, value)

    def get(self, key):  # 主查找
        if self.root:  # 不为空,有节点
            res = self._get(key, self.root)  # 调用副查找
            if res:  # 如果找到了
                return res.payload  # 返回value
            else:  # 反之没找到
                return None
        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):  # 检查树中是否有某个键(in方法)
        if self._get(key, self.root):
            return True
        else:
            return False

    # 主删除
    def delete(self, key):  # 主删除(键)
        if self.size > 1:  # 节点长度>1
            nodeToRemove = self._get(key, self.root)  # 调用查找方法找到你要删除的键
            if nodeToRemove:  # 如果找到了
                self.remove(nodeToRemove)  # 调用删除副方法
                self.size = self.size - 1  # 节点长度-1
            else:  # 没找到了
                raise KeyError('错误,键不在树中')

        # 节点长度==1就只有根节点了==你要找的
        elif self.size == 1 and self.root.key == key:
            self.root = None  # 把根节点设为空
            self.size = self.size - 1  # 节点长度-1

        else:
            raise KeyError('错误,键不在树中')

    def remove(self, currentNode):  # 副删除
        # 情况1.删除节点没有子节点
        if currentNode.isLeaf():  # 如果是叶子节点
            if currentNode == currentNode.parent.leftChild:  # 如果是父节点的左子
                currentNode.parent.leftChild = None  # 就父节点的左子设为空
            else:
                currentNode.parent.rightChild = None  # 就父节点的右子设为空

        # 情况3.有二个节点
        elif currentNode.hasBothChildren():  # 当前节点有两子
            succ = currentNode.findSuccessor()  # 调用寻找后继节点
            succ.spliceOut()  # 调用删除后继节点
            currentNode.key = succ.key  # 当前节点的键等于后继节点的键
            currentNode.payload = succ.payload  # 当前节点的值等于后继节点的值

        #  情况2.有一个节点
        else:
            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
                                                )

    def inorder(self):  # 非递归中序遍历
        currentNode = self.root
        while currentNode:
            beginNode = currentNode
            currentNode = currentNode.leftChild
        while beginNode.findSuccessor():
            print(beginNode.key)
            beginNode = beginNode.findSuccessor()
        print(beginNode.key)


class TreeNode:
    def __init__(self, key, val, left=None, right=None, parent=None, succ=None, balanceFactor=0):
        self.key = key  # 键
        self.payload = val  # 值
        self.leftChild = left  # 左子
        self.rightChild = right  # 右子
        self.parent = parent  # 指针
        self.succ = succ
        self.balanceFactor = balanceFactor  # 平衡因子

    def height(self):  # 树高
        height_l = 0
        height_r = 0
        if self.isLeaf():
            return 0
        if self.leftChild:
            height_l = self.leftChild.height()
        if self.rightChild:
            height_r = self.rightChild.height()
        return max(height_l, height_r) + 1

    def hasLeftChild(self):  # 是否有左子(none就是没有)
        return self.leftChild

    def hasRightChild(self):  # 是否有右子
        return self.rightChild

    def hasAnyChildren(self):  # 是否有孩子
        return self.rightChild or self.leftChild

    def hasBothChildren(self):  # 是否有两孩子
        return self.rightChild and self.leftChild

    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 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  # 右子的指针就指向我自己

    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 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 __iter__(self):  # 二叉搜索树迭代器
        if self:  # 当前节点不为空
            if self.hasLeftChild():  # 当前节点有左子
                for elem in self.leftChild:  # 遍历左子
                    yield elem  # 生成数据
            yield self.key  #
            if self.hasRightChild():  # 当前节点有右子
                for elem in self.rightChild:  # 遍历右子
                    yield elem  # 生成数据


if __name__ == '__main__':
    tree = BinarySearchTree()
    tree[1] = 'a'
    tree[2] = 'b'
    tree[3] = 'c'
    tree[4] = 'd'
    tree[5] = 'e'
    tree[6] = 'f'
    tree[7] = 'g'
    tree[8] = 'h'
    tree[9] = 'i'
    tree[10] = 'j'

    tree.inorder()  # 中序遍历


4.修改二叉搜索树的实现代码,从而实现线索二叉搜索树。为二叉搜索树写一个非递归     的中序遍历方法。线索二叉搜索树为其中的每个节点都维护者指向后继节点的引用。

"""4.修改二叉搜索树的实现代码,从而实现线索二叉搜索树
。为线索二叉搜索树写一个非递归的中序遍历方法。
线索二叉搜索树为其中的每个节点都维护者指向后继节点的引用。"""

class BinarySearchTree:  # 树类
    def __init__(self):
        self.root = None  # 根节点为空
        self.size = 0  # 节点长度为0

    def length(self):  # 返回长度
        return self.size

    def __len__(self):  # 魔法方法返回长度
        return self.size

    def __iter__(self):  # 实现for循环
        return self.root.__iter__()

    def height(self):  # 树高
        return self.root.height()

    # 插入新节点
    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  # 节点长度+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)

        elif key == currentNode.key:  # 练习5 处理重复的键
            currentNode.payload = val
            self.size = self.size + 1

        else:  # 传入的键大于当前节点的键
            if currentNode.hasRightChild():  # 当前节点有右子
                self._put(key, val, currentNode.rightChild)  # 递归调用右子去办
            else:  # 没右子
                # 直接创建一个右子节点赋值给当前右子
                currentNode.rightChild = TreeNode(key, val, parent=currentNode)

    def __setitem__(self, key, value):  # 像字典一样输入
        self.put(key, value)

    # 查找键对应的值
    def get(self, key):  # 主查找
        if self.root:  # 不为空,有节点
            res = self._get(key, self.root)  # 调用副查找
            if res:  # 如果找到了
                return res.payload  # 返回value
            else:  # 反之没找到
                return None
        else:  # 反之为空
            return None


    def _put(self, key, value, currentNode):  # 副查找(键,值,指针)
        if key < currentNode.key:  # 如果查找的键小于当前节点的键
            if currentNode.hasLeftChild():  # 如果当前节点有左子
                self._put(key, value, currentNode.leftChild)  # 递归调用左子去找
            else:  # 没有左子
                currentNode.leftChild = TreeNode(  # 他自己是根节点
                    key, value, parent=currentNode)
                currentNode.leftChild.succ = currentNode  # 当前节点左子的后继节点是当前节点
                if currentNode.parent:  # 如果当前节点有父亲
                    beginNode = currentNode.parent  # 当前节点的父亲赋值给变量
                    while beginNode:  # 无限循环
                        if beginNode.findSuccessor() == currentNode.leftChild:  # 如果父节点的后继是当前节点的左子
                            beginNode.succ = currentNode.leftChild  # 当前节点的左子赋值给父节点的后继
                        beginNode = beginNode.parent  #

        elif key == currentNode.key: # 如果查找的键是当前节点的键
            currentNode.payload = value  # 把值赋值给当前节点的值

        else: # 反之查找的键大于当前节点的键
            if currentNode.hasRightChild():# 如果当前节点有右子
                self._put(key, value, currentNode.rightChild)  # 递归调用右子去找
            else:# 没有右子
                currentNode.rightChild = TreeNode(   # 他自己是根节点
                    key, value, parent=currentNode)
                currentNode.succ = currentNode.rightChild  # 当前节点的后继节点是当前节点的右子
                if currentNode.rightChild.findSuccessor():  
                    currentNode.rightChild.succ = currentNode.rightChild.findSuccessor()

    def __getitem__(self, key):  # 像字典一样查找
        return self.get(key)

    # 检查树中是否有某个键(in方法)
    def __contains__(self, key):
        if self._get(key, self.root):
            return True
        else:
            return False

    # 删除
    def delete(self, key):  # 主删除(键)
        if self.size > 1:  # 节点长度>1
            nodeToRemove = self._get(key, self.root)  # 调用查找方法找到你要删除的键
            if nodeToRemove:  # 如果找到了
                self.remove(nodeToRemove)  # 调用删除副方法
                self.size = self.size - 1  # 节点长度-1
            else:  # 没找到了
                raise KeyError('错误,键不在树中')

        # 节点长度==1就只有根节点了==你要找的
        elif self.size == 1 and self.root.key == key:
            self.root = None  # 把根节点设为空
            self.size = self.size - 1  # 节点长度-1

        else:
            raise KeyError('错误,键不在树中')

    def remove(self, currentNode):  # 副删除
        # 情况1.删除节点没有子节点
        if currentNode.isLeaf():  # 如果是叶子节点
            if currentNode == currentNode.parent.leftChild:  # 如果是父节点的左子
                currentNode.parent.leftChild = None  # 就父节点的左子设为空
            else:
                currentNode.parent.rightChild = None  # 就父节点的右子设为空

        # 情况3.有二个节点
        elif currentNode.hasBothChildren():  # 当前节点有两子
            succ = currentNode.findSuccessor()  # 调用寻找后继节点
            succ.spliceOut()  # 调用删除后继节点
            currentNode.key = succ.key  # 当前节点的键等于后继节点的键
            currentNode.payload = succ.payload  # 当前节点的值等于后继节点的值

        #  情况2.有一个节点
        else:
            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
                                                )

    def __delitem__(self, key):  # 删除(键)
        self.delete(key)

    def inorder(self):  # 中序遍历
        currentNode = self.root
        while currentNode:
            beginNode = currentNode
            currentNode = currentNode.leftChild
        while beginNode.findSuccessor():
            print(beginNode.key)
            beginNode = beginNode.findSuccessor()
        print(beginNode.key)

    def inorder2(self):  # 遍历出后继节点
        currentNode = self.root
        while currentNode:
            beginNode = currentNode
            currentNode = currentNode.leftChild
        while beginNode.succ:
            print(beginNode.key,beginNode.succ)
            beginNode = beginNode.succ
        print(beginNode.key,beginNode.succ)



class TreeNode():
    def __init__(self, key, val, left=None, right=None, succ=None, parent=None):
        self.key = key  # 键
        self.payload = val  # 值
        self.leftChild = left  # 左子
        self.rightChild = right  # 右子
        self.succ = succ  # 后继节点
        self.parent = parent  # 指针
        self.balanceFactor = 0  # 平衡因子

    def height(self):  # 树高
        height_l = 0
        height_r = 0
        if self.isLeaf():
            return 0
        if self.leftChild:
            height_l = self.leftChild.height()
        if self.rightChild:
            height_r = self.rightChild.height()
        return max(height_l, height_r) + 1

    def hasLeftChild(self):  # 是否有左子(none就是没有)
        return self.leftChild

    def hasRightChild(self):  # 是否有右子
        return self.rightChild

    def hasAnyChildren(self):  # 是否有孩子
        return self.rightChild or self.leftChild

    def hasBothChildren(self):  # 是否有两孩子
        return self.rightChild and self.leftChild

    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 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  # 右子的指针就指向我自己

    def __iter__(self):  # 二叉搜索树迭代器
        if self:  # 当前节点不为空
            if self.hasLeftChild():  # 当前节点有左子
                for elem in self.leftChild:  # 遍历左子
                    yield elem  # 生成数据
            yield self.key  #
            if self.hasRightChild():  # 当前节点有右子
                for elem in self.rightChild:  # 遍历右子
                    yield elem  # 生成数据


    # 寻找后继结点
    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 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  # 他右子的父亲等于他的父亲


if __name__ == '__main__':
    tree = BinarySearchTree()
    tree[1] = 'a'
    tree[2] = 'b'
    tree[3] = 'c'
    tree[4] = 'd'
    tree[5] = 'e'
    tree[6] = 'f'
    tree[7] = 'g'
    tree[8] = 'h'
    tree[9] = 'i'
    tree[10] = 'j'

    tree.inorder2()  # 打印后继

 


5.修改二叉搜索树的实现代码,以正确处理重复的键。也就是说,如果键已在树中,就     替换有效载荷,而不是用同一个键插入一个新节点。

"""5.修改二叉搜索树的实现代码,以正确处理重复的键。也就是说,
如果键已在树中,就替换有效载荷,而不是用同一个键插入一个新节点。"""

class BinarySearchTree:  # 树类
    def __init__(self):
        self.root = None  # 根节点为空
        self.size = 0  # 节点长度为0

    def length(self):  # 返回长度
        return self.size

    def __len__(self):  # 魔法方法返回长度
        return self.size

    def __iter__(self):  # 实现for循环
        return self.root.__iter__()

    def height(self):  # 树高
        return self.root.height()

    # 插入新节点
    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  # 节点长度+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)

        elif key == currentNode.key:  # 练习5 处理重复的键
            currentNode.payload = val
            self.size -= 1  # 避免重复计算
            
        else:  # 传入的键大于当前节点的键
            if currentNode.hasRightChild():  # 当前节点有右子
                self._put(key, val, currentNode.rightChild)  # 递归调用右子去办
            else:  # 没右子
                # 直接创建一个右子节点赋值给当前右子
                currentNode.rightChild = TreeNode(key, val, parent=currentNode)

    def __setitem__(self, key, value):  # 像字典一样输入
        self.put(key, value)

    # 查找键对应的值
    def get(self, key):  # 主查找
        if self.root:  # 不为空,有节点
            res = self._get(key, self.root)  # 调用副查找
            if res:  # 如果找到了
                return res.payload  # 返回value
            else:  # 反之没找到
                return None
        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)

    # 检查树中是否有某个键(in方法)
    def __contains__(self, key):
        if self._get(key, self.root):
            return True
        else:
            return False

    # 删除
    def delete(self, key):  # 主删除(键)
        if self.size > 1:  # 节点长度>1
            nodeToRemove = self._get(key, self.root)  # 调用查找方法找到你要删除的键
            if nodeToRemove:  # 如果找到了
                self.remove(nodeToRemove)  # 调用删除副方法
                self.size = self.size - 1  # 节点长度-1
            else:  # 没找到了
                raise KeyError('错误,键不在树中')
                        
        # 节点长度==1就只有根节点了==你要找的
        elif self.size == 1 and self.root.key == key:
            self.root = None  # 把根节点设为空
            self.size = self.size - 1  # 节点长度-1
            
        else:
            raise KeyError('错误,键不在树中')

    def remove(self, currentNode):  # 副删除
        # 情况1.删除节点没有子节点
        if currentNode.isLeaf():  # 如果是叶子节点
            if currentNode == currentNode.parent.leftChild:  # 如果是父节点的左子
                currentNode.parent.leftChild = None  # 就父节点的左子设为空
            else:
                currentNode.parent.rightChild = None  # 就父节点的右子设为空

        # 情况3.有二个节点
        elif currentNode.hasBothChildren():  # 当前节点有两子
            succ = currentNode.findSuccessor()  # 调用寻找后继节点
            succ.spliceOut()  # 调用删除后继节点
            currentNode.key = succ.key  # 当前节点的键等于后继节点的键
            currentNode.payload = succ.payload  # 当前节点的值等于后继节点的值
            
        #  情况2.有一个节点
        else:
            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
                                                )

    def __delitem__(self, key):  # 删除(键)
        self.delete(key)
        
    # 寻找后继结点
    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 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  # 他右子的父亲等于他的父亲


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# 指针
        self.balanceFactor = 0  # 平衡因子

    def height(self):  # 树高
        height_l = 0
        height_r = 0
        if self.isLeaf():
            return 0
        if self.leftChild:
            height_l = self.leftChild.height()
        if self.rightChild:
            height_r = self.rightChild.height()
        return max(height_l, height_r) + 1

    def hasLeftChild(self):  # 是否有左子(none就是没有)
        return self.leftChild

    def hasRightChild(self):  # 是否有右子
        return self.rightChild

    def hasAnyChildren(self):  # 是否有孩子
        return self.rightChild or self.leftChild

    def hasBothChildren(self):  # 是否有两孩子
        return self.rightChild and self.leftChild

    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 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  # 右子的指针就指向我自己

    def __iter__(self):  # 二叉搜索树迭代器
        if self:  # 当前节点不为空
            if self.hasLeftChild():  # 当前节点有左子
                for elem in self.leftChild:  # 遍历左子
                    yield elem  # 生成数据
            yield self.key  #
            if self.hasRightChild():  # 当前节点有右子
                for elem in self.rightChild:  # 遍历右子
                    yield elem  # 生成数据


if __name__ == '__main__':
    tree = BinarySearchTree()
    tree[1] = 'a'
    tree[2] = 'b'
    tree[3] = 'c'
    tree[4] = 'd'
    tree[5] = 'e'
    tree[6] = 'f'
    tree[7] = 'g'
    tree[8] = 'h'
    tree[9] = 'i'
    tree[10] = 'j'
    tree[10] = 'x'
    print('长度为', len(tree))
    print('查找6的值', tree[6])  # 查找
    print(6 in tree)    
    
    print('迭代输出value')
    for a in tree:
        print(tree[a])

    print('迭代输出key')
    for key in tree:
        print(key)
    #print(tree)
    print('高度为', tree.height())
    print('长度为', len(tree))

 6.创建限定大小的二叉堆。也就是说,堆只保持n个最重要的元素。如果堆的大小超过      了n,就会舍弃最不重要的元素。

"""6.创建限定大小的二叉堆。也就是说,堆只保持n个最重要的元素。
如果堆的大小超过了n,就会舍弃最不重要的元素"""

class BinaryHeap:  # 二叉堆类
    def __init__(self, maxsize):  # 定义属性(限定长度)
        self.heapList = [0]  # 定义二叉列表
        self.currentSize = 0  # 定义长度
        self.maxsize = maxsize  # 限定长度

    def percUp(self, i):  # # 处理上移(实例,下标)
        while i // 2 > 0:  # 如果下标除二取整的数大于零
            if self.heapList[i] < self.heapList[i // 2]:  # 当前节点如果他小于了父节点
                temp = self.heapList[i // 2]
                self.heapList[i // 2] = self.heapList[i]  # 调换位置
                self.heapList[i] = temp
            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:  # 如果i*2小于等于长度说明有左子
            mc = self.minChild(i)  # 拿到最小值下标
            if self.heapList[i] > self.heapList[mc]:  # 如果当前左子比左右孙大就交换它俩
                temp = self.heapList[i]
                self.heapList[i] = self.heapList[mc]  # 调换位置
                self.heapList[mc] = temp
            i = mc  # 把当前节点带到下一辈再进行比较

    def minChild(self, i):  # 找到最小值
        if i * 2 + 1 > self.currentSize:  # 如果i*2+1(右子)大于长度说明没有右子
            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  # 列表长度-1
        self.heapList.pop()  # 删除列表最后一位
        self.percDown(1)  # 向下处理
        return retval  # 返回根节点的值

    def buildHeap(self, alist):  # 定义顺序输出函数(构建堆)
        if len(alist) > self.maxsize:  # 如果列表长度大于限定长度
            alist = alist[:self.maxsize]  # 只保留限定长度
        i = len(alist) // 2  # 从儿子辈开始比较
        self.currentSize = len(alist)  # 传入列表长度为堆列表长度
        self.heapList = [0] + alist[:]  # 传入列表全部值前面再加个0赋值给堆列表
        while (i > 0):  # 如果i大于零
            self.percDown(i)  # 调用向下处理方法
            i -= 1  # 长度减一


if __name__ == '__main__':
    heap = BinaryHeap(10)  # 创建对象(限定长度)
    alist = [11, 5, 9, 21, 17, 19, 18, 27, 14, 33, 90, 88]
    heap.buildHeap(alist)  # 构建堆
    print(heap.heapList)  # 打印堆

 7.整理printexp函数,去掉数字周围多余的括号。

"""7.整理printexp函数,去掉数字周围多余的括号"""
import operator
class BinaryTree:
	# 初始化二叉树
	def __init__(self, rootObj):  # 根节点 
		self.root = 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.root = obj

	# 获取根节点值
	def getRootVal(self):
		return self.root
        
# 中序遍历函数
def inorder(tree):
    if tree:  # 若树不为None,则
        inorder(tree.getLeftChild())  # 中序遍历左子树
        print(tree.getRootVal())  # 打印根节点值
        inorder(tree.getRightChild())  # 中序遍历右子树

# 后序遍历函数
def postorder(tree):
    if tree:  # 若树不为None,则
        postorder(tree.getLeftChild())  # 后序遍历左子树
        postorder(tree.getRightChild())  # 后序遍历右子树
        print(tree.getRootVal())  # 打印根节点值

# 前序遍历函数
def preorder(tree):
    if tree:  # 若树不为None,则
        print(tree.getRootVal())  # 打印根节点值
        preorder(tree.getLeftChild())  # 前序遍历左子树
        preorder(tree.getRightChild())  # 前序遍历右子树

# 形成表达式
def printexp(tree):
    sVal = ""  # 表达式初始为空字符
    if tree:  # 有树
        sVal = '(' + printexp(tree.getLeftChild())  # (+左子
        sVal = sVal + str(tree.getRootVal())  # (+左子+根节点
        sVal = sVal + printexp(tree.getRightChild()) + ')'  # (+左子+根节点+右子+)
    return sVal

# # 改进版(去掉数字周围多余括号的表达式)
def printexp1(tree):
    sVal = ''  # 表达式初始为空字符
    if tree:  # 有树
        if tree.leftChild == None and tree.rightChild == None:  # 无左子和无右子
            sVal = sVal + str(tree.getRootVal())  # 根节点
        else:  # 反之
            sVal = '(' + printexp1(tree.getLeftChild())  # (+左子
            sVal = sVal + str(tree.getRootVal())  # (+左子+根节点
            sVal = sVal + printexp1(tree.getRightChild()) + ')'  # (+左子+根节点+右子+)
    return sVal

# 后续计算表达式的值
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()  # 返回根节点

# 树高
def height(tree):
    if tree == None: # 出口
        return -1
    else:  # max(递归左子,递归右子)
        return 1 + max(height(tree.leftChild), height(tree.rightChild))

t = BinaryTree(7)  # 创建对象(根节点)
t.insertLeft(3)  # 添加(左子)
t.insertRight(9)  # 添加(右子)
inorder(t)  # 中序遍历

x = BinaryTree('*')  # 创建对象(根节点)
x.insertLeft('+')  # 添加(左子)
l = x.getLeftChild()  # 获取左子
l.insertLeft(4)  # 添加(左子)
l.insertRight(5)  # 添加(右子)
x.insertRight(7)  # 添加(右子)
print(printexp(x))  # 原版
print(printexp1(x))  # 改进版(去掉数字周围多余括号的表达式)
print(postordereval(x))  # 计算表达式的值
print(height(x))  # 树高


 8.使用buildHeap方法,针对列表写一个时间复杂度为O ( l o g n ) O(logn)O(logn)的      排序函数。

class BinaryHeap:
    def __init__(self, maxsize):
        self.heapList = [0]  # 装数据的列表
        self.currentSize = 0  # 列表长度
        self.maxsize = maxsize  # 堆的最大长度

    def percUp(self, i):  # 处理上移(下标)
        while i // 2 > 0:  # 只要下标大于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  # 列表长度加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  # 列表长度-1
        self.heapList.pop()  # 删除列表最后一个
        self.percDown(1)  # 再把顶替第一的进行向下处理
        return retval  # 返回列表第一个


    # 根据元素列表构建堆
    def buildHeap(self, alist):  # 对列表进行排序(列表)
        if len(alist) > self.maxsize:  # 列表长度>堆最大长度
            alist = alist[:self.maxsize]  # 从左开始只取出堆最大长度的元素
        i = len(alist) // 2  # 返回列表长度的一半
        self.currentSize = len(alist)  # 返回传入列表长度赋值给堆列表长度
        self.heapList = [0] + alist[:]  # 把传入列表的数据取出来前面加个0赋值给堆列表
        while (i > 0):  # 下标大于0就循环
            self.percDown(i)  # 调用处理下移
            i -= 1  # 长度-1 


def sort(alist):  # 排序
    heap = BinaryHeap(13)  # 创建对象
    blist = [0]  # 定义空堆
    heap.buildHeap(alist)  # 重新排列
    for i in range(1, len(alist) + 1):  # 列表长度-1
        if heap.currentSize > 0:  # 列表长度
            blist += [heap.heapList[1]]   # 把堆列表的元素赋值给新定义的空堆
        heap.buildHeap(heap.heapList[2:])  # 把第二个到最后重新排列
    print(blist)  # 打印堆


if __name__ == '__main__':

    alist = [9, 6, 5, 2, 39, 16, 15, 12, 389, 26, 25, 22, 33]
    sort(alist)

 9.写一个函数,以数学表达式解析树为参数,计算各变量的导数。

&


10.将二叉树实现为最大堆。 

"""10.将二叉树实现为最大堆。最大堆的实现"""
class MaxHeap():
    def __init__(self, maxSize=None):
        self.maxSize = maxSize
        self.li = [None] * maxSize
        self.count = 0

    def length(self):
        #求数组的长度
        return self.count

    def show(self):
        if self.count <= 0:
            print('null')
        else:
            print(self.li[: self.count])

    def add(self, value):
        if self.count >= self.maxSize:  # 判断是否数组越界
            raise Exception('full')

        self.li[self.count] = value  # 将新节点增加到最后
        self._shift_up(self.count)  # 递归构建大堆
        self.count += 1

    def _shift_up(self, index):
        #往大堆中添加元素,并保证根节点是最大的值:
        #1.增加新的值到最后一个结点,在add实现; 2.与父节点比较,如果比父节点值大,则交换
        if index > 0:
            parent = (index - 1) // 2  # 找到根节点
            if self.li[index] > self.li[parent]:  # 交换结点
                self.li[index], self.li[parent] = self.li[parent], self.li[index]
                self._shift_up(parent)  # 继续递归从底往上判断

    def extract(self):
        #弹出最大堆的根节点,即最大值
        #1.删除根结点,将最后一个结点作为更结点 ; 2.判断根结点与左右结点的大小,交换左右结点较大的
        if not self.count:
            raise Exception('null')
        value = self.li[0]
        self.count -= 1
        self.li[0] = self.li[self.count]  # 将最后一个值变为第一个
        self._shift_down(0)
        return value

    def _shift_down(self, index):
        # 1.判断是否有左子节点并左大于根,左大于右;2.判断是否有右子节点,右大于根
        left = 2 * index + 1
        right = 2 * index + 2
        largest = index

        #判断条件
# 下面2个条件包含了,判断左右结点那个大的情况。如果为3, 4, 5,:
# 第一个判断条件使得largest = 1,再执行第二个条件,则判断其左结点与右结点的大小
        if left < self.length() and self.li[left] > self.li[largest]:
            largest = left
        if right < self.length() and self.li[right] > self.li[largest]:
            largest = right

        if largest != index: # 将 两者交换
            self.li[index], self.li[largest] = self.li[largest], self.li[index]
            self._shift_down(largest)
    

if __name__ == '__main__':
    m = MaxHeap(10)
    import numpy as np 
    np.random.seed(123)
    num = np.random.randint(100, size =10) #创建随机的10个数
    print(m.length())
    for i in num:
        m.add(i)
    m.show()    
    print(m.length())     
    for i in range(10):
        print(m.extract(), end=' ,')


 11.使用BinaryHeap类。实现一个叫做PriorityQueue的新类。为PriorityQueue类实         现构造方法,以及enqueue方法和dequeue方法。

"""11.使用BinaryHeap类。实现一个叫做PriorityQueue的新类
。为PriorityQueue类实现构造方法,以及enqueue方法和dequeue方法"""

class BinaryHeap:
    # 新建二叉堆
    def __init__(self):
        self.heapList = [0]  # 装数据的列表
        self.currentSize = 0  # 列表长度

    def percUp(self, i):  # 处理上移(下标)
        while i // 2 > 0:  # 只要下标大于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  # 列表长度加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  # 列表长度-1
        self.heapList.pop()  # 删除列表最后一个
        self.percDown(1)  # 再把顶替第一的进行向下处理
        return retval  # 返回列表第一个

    ## 根据元素列表构建堆
    def builgHeap(self, alist):  # 对列表进行排序(列表)
        i = len(alist) // 2  #
        self.currentSize = len(alist)  # 返回传入列表长度赋值给列表长度
        self.heapList = [0] + alist[:]  # 把传入列表的数据取出来前面加个0定义成
        while (i > 0):  # 下标大于0就循环
            self.percDown(i)  #
            i = i - 1


class PriorityQueue:  # 优先队列 
    def __init__(self):  # 初始为空的列表
        self.items = []

    def isEmpty(self):  # 检查列表
        return self.items == []

    def enqueue(self, item):  # 入队
        self.items.append(item)  # 添加列表尾部
        heap = BinaryHeap()  # 创建堆对象
        heap.builgHeap(self.items)  # 根据元素列表构建堆
        self.items = heap.heapList[1:]  # 取出堆列表赋值给队列

    def dequeue(self):  # 出队
        return self.items.pop(0)  # 删除列表第一个

    def size(self):  # 返回列表长度
        return len(self.items)


if __name__ == '__main__':
    q = PriorityQueue()
    q.enqueue(5)  # 进队
    q.enqueue(2)
    q.enqueue(3)
    q.enqueue(6)
    q.enqueue(1)

    print(q.items)  # 打印列表

    q.dequeue()  # 出队
    q.dequeue()
    print(q.items)

 12.实现AVL树的delete方法。实现AVL的delete方法,要更新平衡因子,然后再平衡。

"""12.实现AVL树的delete方法。实现AVL的delete方法"""

def aaa(node):  # 中序遍历
    if node != None:
        aaa(node.leftChild)
        print(node.key)        
        aaa(node.rightChild)

class BinarySearchTree:  # 二叉搜索树类
    def __init__(self):  # 初始属性
        self.root = None  # 根节点为空
        self.size = 0  # 节点长度为0
    def __str__(self):
        return self.root
    def length(self):  # 返回长度
        return self.size

    def __len__(self):  # 魔法方法返回长度
        return self.size

    def __iter__(self):  # 实现for循环
        return self.root.__iter__()

    def height(self):  # 返回树高
        if self.root != None:
            return self.root.height()
        else:
            print('没有树')

    def put(self, key, value):  # 主添加(键,值)
        if self.root:  # 不为空,有节点
            self._put(key, value, self.root)  # 调用辅助添加方法(键,值,指针)
        else:  # 反之
            self.root = TreeNode(key, value)  # 创建对象传入(键,值)
        self.size = self.size + 1  # 节点长度+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, key, value):  # 像字典一样输入
        self.put(key, value)

    def get(self, key):  # 主查找
        if self.root:  # 不为空,有节点
            res = self._get(key, self.root)  # 调用副查找
            if res:  # 如果找到了
                return res.payload  # 返回value
            else:  # 反之没找到
                return None
        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):  # 检查树中是否有某个键(in方法)
        if self._get(key, self.root):
            return True
        else:
            return False

    def delete(self, key):  # 主删除(键)
        if self.size > 1:  # 节点长度>1
            nodeToRemove = self._get(key, self.root)  # 调用查找方法找到你要删除的键
            if nodeToRemove:  # 如果找到了
                self.remove(nodeToRemove)  # 调用删除副方法
                self.size -= 1  # 节点长度-1
            else:  # 没找到了
                print('错误,键不在树中')
        # 节点长度==1就只有根节点了==你要找的
        elif self.size == 1 and self.root.key == key:
            self.root = None  # 把根节点设为空
            self.size = 0  # 节点长度为0
        else:
            print('错误,键不在树中')

    def remove(self, currentNode):  # 副删除方法
        # 情况1.删除节点没有子节点
        if currentNode.isLeaf():  # 如果是叶子节点            
            if currentNode == currentNode.parent.leftChild: # 如果是父节点的左子 
                currentNode.parent.leftChild = None  # 就父节点的左子设为空
            else:  # 反之
                currentNode.parent.rightChild = None  # 就父节点的右子设为空

        #  情况2.有一个节点
        # 如果当前节点有左子和没右子
        elif currentNode.hasLeftChild() and not currentNode.hasRightChild():
            if currentNode.isLeftChild():  # 他自己是左子
                # 当前左子的父亲等于当前节点的父亲
                currentNode.leftChild.parent = currentNode.parent  # 
                # 当前节点父亲的左子等于当前节点的左子
                currentNode.parent.leftChild = currentNode.leftChild
            elif currentNode.isRightChild():# 他自己是右子
                # 当前右子的父亲等于当前节点的父亲等于当前节点的父亲
                currentNode.rightChild.parent = currentNode.parent
                # 当前节点父亲的右子等于当前节点的左子
                currentNode.parent.rightChild = currentNode.leftChild
            else:  # 反之他没父节点就是根节点了(他儿子继承他父亲的一切)
                currentNode.replaceNodeData(currentNode.leftChild.key,
                                            currentNode.leftChild.payload,
                                            currentNode.leftChild.leftChild,
                                            currentNode.leftChild.rightChild)

        #  如果当前节点有右子和没左子                                   
        elif currentNode.hasRightChild() and not currentNode.hasLeftChild():
            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.leftChild.key,
                                            currentNode.leftChild.payload,
                                            currentNode.leftChild.leftChild,
                                            currentNode.leftChild.rightChild)
        # 情况3.有二个节点
        else:  # 反之有二子
            succ = currentNode.findSuccessor()  # 调用寻找后继节点
            succ.spliceOut()  # 调用删除后继节点
            currentNode.key = succ.key  # 当前节点的键等于后继节点的键
            currentNode.payload = succ.payload# 当前节点的值等于后继节点的值

    def __delitem__(self, key):  # 像字典一样删除
        self.delete(key)
        
class TreeNode:  # 节点类
    def __init__(self, key, val, left=None, right=None, parent=None, succ=None, balanceFactor=0):
        self.key = key  # 键
        self.payload = val  # 值
        self.leftChild = left  # 左子
        self.rightChild = right  # 右子
        self.parent = parent  # 指针
        self.succ = succ  # 后继节点
        self.balanceFactor = balanceFactor  # 平衡因子

    def height(self):  # 树高
        height_l = 0  # 左高
        height_r = 0  # 右高
        if self.leftChild:  # 如果有左子
            height_l = self.leftChild.height()  # 左子高度
        if self.rightChild:  # 如果有右子
            height_r = self.rightChild.height()  # # 右子高度
        return max(height_l, height_r) + 1  # 返回树高+1

    def hasLeftChild(self):  # 是否有左子(none就是没有)
        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.leftChild and self.rightChild  # 返回左子和右子

    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  # 右子的指针就指向我自己

    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 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 __iter__(self):  # 二叉搜索树迭代器
        if self:  # 当前节点不为空
            if self.hasLeftChild():  # 当前节点有左子
                for elem in self.leftChild:  # 遍历左子
                    yield elem  # 生成数据
            yield self.key  #
            if self.hasRightChild():  # 当前节点有右子
                for elem in self.rightChild:  # 遍历右子
                    yield elem  # 生成数据

class AVL(BinarySearchTree):  # 更改为平衡二叉树(继承二叉搜索树类)
    # 1.修改辅助添加
    def _put(self, key, value, currentNode):  # 辅助添加(键,值,指针)
        if key < currentNode.key:  # 如果传入的键小于当前节点的键
            if currentNode.hasLeftChild():  # 当前节点有左子
                self._put(key, value, currentNode.leftChild)  # 递归调用左子去办
            else:  # 没左子
                currentNode.leftChild = TreeNode(  # 直接创建一个左子节点赋值给当前左子
                    key, value, parent=currentNode)
                self.updateBalance(currentNode.leftChild)  # 更新平衡因子
        else:  # 反之传入的键大于当前节点的键
            if currentNode.hasRightChild():  # 当前节点有右子
                self._put(key, value, currentNode.rightChild)  # 递归调用右子去办
            else:  # 没右子
                currentNode.rightChild = TreeNode(  # 直接创建一个右子节点赋值给当前右子
                    key, value, parent=currentNode)
                self.updateBalance(currentNode.rightChild)  # 更新平衡因子

    # 2.添加更新平衡因子(添加时用)
    def updateBalance(self, node):  # 更新平衡因子
        # 如果节点的因子>1或节点的因子< -1
        if node.balanceFactor > 1 or node.balanceFactor < -1:
            self.rebalance(node)  # 调用再平衡方法
            return  # 返回
        if node.parent != None:  # 如果当前节点父亲不为空
            if node.isLeftChild(): # 如果当前节点是左子
                node.parent.balanceFactor += 1  # 当前节点父亲的平衡因子+1
            elif node.isRightChild():  # 如果当前节点是右子
                node.parent.balanceFactor -= 1 # 当前节点父亲的平衡因子-1

            if node.parent.balanceFactor != 0:  # 当前节点父亲的平衡因子不等于0
                self.updateBalance(node.parent)  # 递归调用自己向上找

    # 3.添加更新平衡因子(删除时用)
    def updateBalance2(self, node):  # 更新平衡因子
        # 如果节点的因子>1或节点的因子< -1
        if node.balanceFactor > 1 or node.balanceFactor <= -1:
            self.rebalance(node)  # 调用再平衡方法
            return  # 返回
        if node.parent != None:  # 如果当前节点父亲不为空
            if node.isLeftChild():  # 如果当前节点是左子
                node.parent.balanceFactor -= 1  # 当前节点父亲的平衡因子-1
            elif node.isRightChild():  # 如果当前节点是右子
                node.parent.balanceFactor += 1  # 当前节点父亲的平衡因子+1

            if node.parent.balanceFactor != 0:  # 当前节点父亲的平衡因子不等于0
                self.updateBalance2(node.parent)  # 递归调用自己向上找
                
    # 4.修改删除后继节点
    def spliceOut2(self):  # 删除后继节点
        if self.isLeaf():# 如果没子节点
            if self.isLeftChild():# 如果自己是左子
                self.parent.leftChild = None# 把他父亲的左子变成空
                self.parent.balanceFactor -= 1  # 他父亲的平衡因子-1
            else:# 反之自己是右子
                self.parent.rightChild=None  # 把他父亲的右子变成空
                self.parent.balanceFactor += 1# 他父亲的平衡因子+1
        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#他父亲的左子等于他的右子
                    self.parent.balanceFactor -= 1 # 他父亲的平衡因子-1
                else:# 反之自己是右子
                    self.parent.rightChild = self.rightChild# 把他父亲的右子等于他的右子
                    self.parent.balanceFactor += 1# 他父亲的平衡因子+1

                self.rightChild.parent = self.parent# 他右子的父亲等于他的父亲

    # 5.添加左旋
    def rotateLeft(self, rotRoot):  # 左旋方法
        newRoot = rotRoot.rightChild  # 新节点=旧节点的右子
        rotRoot.rightChild = newRoot.leftChild  # 老节点的右子=新节点的左子
        if newRoot.leftChild != None:  # 新节点的左子不为空
            newRoot.leftChild.parent = rotRoot  # 新节点的左子的爸爸=老节点
        newRoot.parent = rotRoot.parent  # 新节点的爸爸=老节点的爸爸
        if rotRoot.isRoot():  # 如果旧节点是根节点
            self.root = newRoot  # 根节点是新节点
        else:  # 反旧节点不是之根节点
            if rotRoot.isLeftChild():  # 如果旧节点是左子
                rotRoot.parent.leftChild = newRoot  # 旧节点爸爸的左子=新节点
            else:  # 如果旧节点是右子
                rotRoot.parent.rightChild = newRoot  # 旧节点爸爸的右子=新节点
        newRoot.leftChild = rotRoot  # 新节点的左子 = 旧节点
        rotRoot.parent = newRoot  # 旧节点的爸爸 = 新节点
        # 旧因子=旧因子+1-()
        rotRoot.balanceFactor = rotRoot.balanceFactor + \
            1 - min(newRoot.balanceFactor, 0)
        # 新因子=新因子
        newRoot.balanceFactor = newRoot.balanceFactor + \
            1 + max(rotRoot.balanceFactor, 0)

    # 6.添加右旋
    def rotateRight(self, rotRoot):  # 右旋方法
        newRoot = rotRoot.leftChild  # 新节点=旧节点的左子
        rotRoot.leftChild = newRoot.rightChild  # 旧节点的左子=新节点的右
        if newRoot.rightChild != None:  # 如果新节点的右子不等于空
            newRoot.rightChild.parent = rotRoot  # 新节点右子的爸爸 = 旧节点
        newRoot.parent = rotRoot.parent  # 新节点的爸爸 = 旧节点的爸爸
        if rotRoot.isRoot():  # 如果旧节点是根节点
            self.root = newRoot  # 根节点就是新节点
        else:  # 反之旧节点不是根节点
            if rotRoot.isRightChild():  # 如果旧节点是右子
                rotRoot.parent.rightChild = newRoot  # 旧节点的爸爸的右子 = 新节点
            else:  # 反之旧节点是左子
                rotRoot.parent.leftChild = newRoot  # 旧节点的爸爸的左子 = 新节点
        newRoot.rightChild = rotRoot  # 新节点右子 = 旧节点
        rotRoot.parent = newRoot  # 旧节点的爸爸 = 新节点
        # 旧因子=旧因子-1-max(新因子,0)
        rotRoot.balanceFactor = rotRoot.balanceFactor - \
            1 - max(newRoot.balanceFactor, 0)
        # 新因子=新因子-1+man(新因子,0)
        newRoot.balanceFactor = newRoot.balanceFactor - \
            1 + min(rotRoot.balanceFactor, 0)

    # 7.添加实现再平衡
    def rebalance(self, node):  # 实现再平衡
        if node.balanceFactor < 0:  # 当前节点因子<0(右高)
            if node.rightChild.balanceFactor > 0:  # 当前节点右子因子>0(右子高)
                self.rotateRight(node.rightChild)  # 先对根节点的右子做一个右旋转
                self.rotateLeft(node)  # 再对根节点做一个左旋转
            else:
                self.rotateLeft(node)  # 直接对根节点做一个左旋转
        elif node.balanceFactor > 0:  # 当前节点因子>0(左高)
            if node.leftChild.balanceFactor < 0:  # 当前节点左子因子>0(左子高)
                self.rotateLeft(node.leftChild)  # 先对根节点的左子做一个左旋转
                self.rotateRight(node)  # 再对根节点做一个右旋转
            else:
                self.rotateRight(node)  # 直接对根节点做一个左旋转
    # 8.修改主删除
    def delete1(self, key):# 删除(键)
        if self.size > 1: # 节点长度>1
            nodeToRemove = self._get(key, self.root) # 调用查找方法找到你要删除的键
            if nodeToRemove:# 如果找到了
                self.remove1(nodeToRemove)  # 调用删除副方法
                self.size -= 1 # 节点长度-1
            else:# 没找到了
                raise KeyError('错误,键不在树中')
        elif self.size == 1 and self.root.key == key:# 节点长度==1就只有根节点了==你要找的
            self.root = None # 把根节点设为空
            self.size = 0# 节点长度为0
        else:
            raise KeyError('错误,键不在树中')

    # 9.修改副删除
    def remove1(self, currentNode):# 副删除方法
         # 情况1.删除节点没有子节点
        if currentNode.isLeaf():# 如果是叶子节点
            if currentNode == currentNode.parent.leftChild:# 如果是父节点的左子
                currentNode.parent.leftChild = None# 就父节点的左子设为空
                currentNode.parent.balanceFactor -= 1# 当前节点父亲的平衡因子-1
            else:# 反之
                currentNode.parent.rightChild = None# 就父节点的右子设为空
                currentNode.parent.balanceFactor += 1# 当前节点父亲的平衡因子+1
            self.updateBalance2(currentNode.parent) # 更新平衡因子

        #  情况2.有一个节点
        # 如果当前节点有左子和没右子    
        elif currentNode.hasLeftChild() and not currentNode.hasRightChild():
            if currentNode.isLeftChild():# 他自己是左子
                # 当前左子的父亲等于当前节点的父亲
                currentNode.leftChild.parent = currentNode.parent
                # 当前节点父亲的左子等于当前节点的左子
                currentNode.parent.leftChild = currentNode.leftChild
                # 当前节点父亲的平衡因子-1
                currentNode.parent.balanceFactor -= 1
            elif currentNode.isRightChild():# 他自己是右子
                # 当前右子的父亲等于当前节点的父亲等于当前节点的父亲
                currentNode.rightChild.parent = currentNode.parent
                # 当前节点父亲的右子等于当前节点的左子
                currentNode.parent.rightChild = currentNode.leftChild
                # 当前节点父亲的平衡因子+1
                currentNode.parent.balanceFactor += 1
            else:# 反之他没父节点就是根节点了(他儿子继承他父亲的一切)
                currentNode.replaceNodeData(currentNode.leftChild.key,
                                            currentNode.leftChild.payload,
                                            currentNode.leftChild.leftChild,
                                            currentNode.leftChild.rightChild)
            #self.updateBalance2(currentNode.parent) # 更新平衡因子
        #  如果当前节点有右子和没左子    
        elif currentNode.hasRightChild() and not currentNode.hasLeftChild():
            if currentNode.isLeftChild():# 他自己是左子
                # 当前右子的父亲等于当前节点的父亲等于当前节点的父亲
                currentNode.rightChild.parent = currentNode.parent
                # 当前节点父亲的左子等于当前节点的右子
                currentNode.parent.leftChild = currentNode.rightChild
                # 当前节点父亲的平衡因子-1
                currentNode.parent.balanceFactor -= 1
            elif currentNode.isRightChild():# 他自己是右子
                # 当前右子的父亲等于当前节点的父亲等于当前节点的父亲
                currentNode.rightChild.parent = currentNode.parent
                # 当前节点父亲的右子等于当前节点的右子
                currentNode.parent.rightChild = currentNode.rightChild
                # 当前节点父亲的平衡因子+1
                currentNode.parent.balanceFactor += 1
            else:  # 反之他没父节点就是根节点了(他儿子继承他父亲的一切)
                currentNode.replaceNodeData(currentNode.rightChild.key,
                                            currentNode.rightChild.payload,
                                            currentNode.rightChild.leftChild,
                                            currentNode.rightChild.rightChild)
            #self.updateBalance2(currentNode.parent)  # 更新平衡因子
                #currentNode.balanceFactor = 0
        # 情况3.有二个节点
        else:# 反之有二子
            succ = currentNode.findSuccessor()# 调用寻找后继节点
            succ.spliceOut()# 调用删除后继节点
            self.updateBalance2(currentNode)  # 更新平衡因子
            currentNode.key = succ.key# 当前节点的键等于后继节点的键
            currentNode.payload = succ.payload# 当前节点的值等于后继节点的值

    # 10.查看中序遍历和平衡因子(中序遍历非递归写法)
    def inorder(self):  # 中序遍历
        currentNode = self.root  # 根节点赋值给变量
        while currentNode:  # 
            beginNode = currentNode
            currentNode = currentNode.leftChild  # 
        while beginNode.findSuccessor():
            print(beginNode.key, beginNode.balanceFactor)
            beginNode = beginNode.findSuccessor()
        print(beginNode.key, beginNode.balanceFactor)  # 

    def inorder2(self):
        currentNode = self.root
        while currentNode:
            beginNode = currentNode
            currentNode = currentNode.leftChild
        while beginNode.succ:
            print(beginNode.key)
            beginNode = beginNode.succ
        print(beginNode.key)


if __name__ == '__main__':
    tree = AVL()
    tree[1] = 'a'
    tree[2] = 'b'
    tree[3] = 'c'
    tree[4] = 'd'
    tree[5] = 'e'
    tree[6] = 'f'
    tree[7] = 'g'
    tree[8] = 'h'
    tree[9] = 'i'
    tree[10] = 'j'   

    print('原始高度为:', tree.height())
    print('原始长度为:',len(tree))
    print('查找5在不在:', 5 in tree)
    print('查找1的值:', tree[1])  # 查找
    #tree.delete1(1)
    #tree.delete1(2)
    # tree.delete1(3)
    #tree.delete1(4)
    #tree.delete1(5)
    #tree.delete1(6)
    # tree.delete1(7)
    #tree.delete1(8)
    #tree.delete1(9)
    #tree.delete1(10)
    print('删除后高度为', tree.height())
    print('删除后长度为', len(tree))    
    print('-'*20)
    print('迭代输出value')
    for a in tree:
        print(tree[a])
    print('-'*20)
    print('迭代输出key')
    for key in tree:
        print(key)

    print('-'*20)
    print(aaa(tree.root))
    tree.inorder()
    # tree.inorder2()

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值