python代码——树和二叉树

python代码——树和二叉树

原理可参考链接:https://blog.csdn.net/qq_32640443/article/details/109812861

生成二叉树:

"""构建结点类"""
class BTNode(object):
    def __init__(self, val=None, lchild=None, rchild=None):
        self.val = val
        self.lchild = lchild
        self.rchild = rchild

"""构建二叉树类"""
class BiTree(object):
    def __init__(self, data_list):
        #初始化,即将传入的列表的迭代器
        self.it = iter(data_list)
    """
    iter函数和next函数共同使用
    next函数返回迭代器中的下一个项目,即遍历玩迭代器中的元素
    """
    def createBiTree(self, bt=None): 
        """创建二叉树"""
        try:
            #获取下一个元素
            next_data = next(self.it)
            #如果当前列表元素为'#', 则认为其为 None
            if next_data == "#":
                bt = None
            else:
                bt = BTNode(next_data)
                bt.lchild = self.createBiTree(bt.lchild)
                bt.rchild = self.createBiTree(bt.rchild)
        # 异常处理
        except Exception as e:
            print(e)
        return bt

    def preOrderTrave(self, bt):
        """递归前序遍历"""
        if bt is not None:
            print(bt.val, end=" ")
            self.preOrderTrave(bt.lchild)
            self.preOrderTrave(bt.rchild)

    def preOrder_non_recursive(self, bt):
        """借助栈非递归前序遍历"""
        if bt == None:
            return
        stack = []
        while bt or len(stack) > 0:
            if bt:
                stack.append(bt)
                print(bt.val, end=' ')
                bt = bt.lchild
            else:
                bt = stack[-1]
                stack.pop()
                bt = bt.rchild

    def inOrderTrave(self, bt):
        """递归中序遍历"""
        if bt is not None:
            self.inOrderTrave(bt.lchild)
            print(bt.val, end=" ")
            self.inOrderTrave(bt.rchild)

    def inOrder_non_recursive(self, bt):
        """借助栈非递归中序遍历"""
        if bt == None:
            return
        stack = []
        while bt or len(stack) > 0:
            if bt:
                stack.append(bt)
                bt = bt.lchild
            else:
                bt = stack.pop()
                print(bt.val, end=' ')
                bt = bt.rchild

    def postOrderTrave(self, bt):
        """递归后序遍历"""
        if bt is not None:
            self.postOrderTrave(bt.lchild)
            self.postOrderTrave(bt.rchild)
            print(bt.val, end=" ")

    def postOrder_non_recursive(self, bt):
        """借助栈非递归后序遍历"""
        if bt == None:
            return
        stack1 = []
        stack2 = []
        stack1.append(bt)
        while stack1:
            node = stack1.pop()
            if node.lchild:
                stack1.append(node.lchild)
            if node.rchild:
                stack1.append(node.rchild)
            stack2.append(node)
        while stack2:
            print(stack2.pop().val, end=' ')
        return

    def tree_deep(self, root):
        """二叉树的深度""" 
        if not root:
            return 0
        left = self.tree_deep(root.lchild)+1
        right = self.tree_deep(root.rchild)+1
        return left if left>right else right
    
    def leave(self,root):
        """递归求二叉树结点数目"""
        if root == None:
            return 0
        else:
            a = (1+self.leave(root.lchild)+self.leave(root.rchild))
        return a

    def copy(self,root):
        """复制一棵树"""
        if not root:
            return
        NewTree = BTNode(root.val)
        NewTree.left = self.copy(root.lchild)
        NewTree.right = self.copy(root.rchild)
        return NewTree

    # 综合打印
    def printTrave(self, bt):
        print("先序遍历: ", end="")
        self.preOrderTrave(bt)
        print('\n')
        print("先序遍历: ", end="")
        self.preOrder_non_recursive(bt)
        print('\n')        
        print("中序遍历: ", end="")
        self.inOrderTrave(bt)
        print('\n')
        print("中序遍历: ", end="")
        self.inOrder_non_recursive(bt)
        print('\n')        
        print("后序遍历: ", end="")
        self.postOrderTrave(bt)
        print('\n')
        print("后序遍历: ", end="")
        self.postOrder_non_recursive(bt)
        print('\n')
       
        print("二叉树的深度:",end="")
        print(self.tree_deep(bt))
        print("二叉树的结点数:",end="")
        print(self.leave(bt))
        print("复制该二叉树:",end="")
        print(self.copy(bt))


data = input("Please input the node value: ")
data_list = list(data)

btree = BiTree(data_list)
root = btree.createBiTree()
btree.printTrave(root)

中序线索化二叉树:

"""构建结点类"""
class TreeNode(object):
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
        # 如果left_label==0 表示指向的是左子树,如果是1 则表示指向前驱结点
        # 如果right_label==0 表示指向的是右子树,如果是1 怎表示指向后继结点
        self.left_label = 0 # 注意这里必须写0,不能写空值
        self.right_label = 0

"""构建线索二叉树的类"""
class ThreadedBinaryTree(object):
    def __init__(self):
        self.root = None
        # 在递归进行线索化,总是保留前一个结点
        self.pre = None  # 为实现线索化,需要创建给指向当前结点的前驱结点指针

    def in_order(self, node):
        """二叉树中序遍历"""
        if node is None:
            return
        self.in_order(node.left)
        print(node.val, end=' ')
        self.in_order(node.right)
    
    
    def threaded_node(self, node):  # node: 就是当前需要线索化的结点
        """二叉树进行中序线索化"""   #线索化的过程就是在遍历的过程中修改空指针的过程
        if node is None:
            return
        # 先线索化左子树
        self.threaded_node(node.left)
        
        # 线索化当前结点
        # 处理当前结点的前驱结点
        if node.left is None:  # 如果当前结点左子结点为空
            node.left = self.pre  # 让当前结点的左指针指向前驱结点
            node.left_label = 1  # 修改当前结点的左指针类型 为 前驱结点
        # 处理当前结点的后继结点
        if self.pre and self.pre.right is None: 
            self.pre.right = node  # 让前驱结点的右指针指向当前结点
            self.pre.right_label = 1  # 修改前驱结点的右指针类型
        self.pre = node  # 每处理一个结点后,让当前结点是下一个结点的前驱结点
        
        # 线索化右子树
        self.threaded_node(node.right)
        
    def threaded_in_order(self, node):
        """中序遍历线索化二叉树"""
        if node is None:
            return
        temp_node = node
        while temp_node:
            # 循环的找到left_label=1的结点,第一个找到就是值为8的结点
            # 后面随着遍历而变化,因为当left_label=1时,说明该结点是按照线索化处理后的有效结点
            while temp_node.left_label == 0:  # 从根结点开始向左找,找到第一个1停止
                temp_node = temp_node.left
            # 打印当前这个结点
            print(temp_node.val, end=" ")
            # 如果当前结点的右指针指向的是后继结点,就一直输出
            while temp_node.right_label == 1:
                # 获取到当前结点的后继结点
                temp_node = temp_node.right
                print(temp_node.val, end=" ")
            # 如果不等于1了,就替换这个遍历的结点
            temp_node = temp_node.right

"""测试代码"""
if __name__ == '__main__':
    t = ThreadedBinaryTree()
    # 手动创建结点--只是为了更好测试线索化有没有成功
    t1 = TreeNode(1)
    t2 = TreeNode(3)
    t3 = TreeNode(6)
    t4 = TreeNode(8)
    t5 = TreeNode(10)
    t6 = TreeNode(14)
    t1.left = t2
    t1.right = t3
    t2.left = t4
    t2.right = t5
    t3.left = t6
    print("原来的二叉树中序遍历为:")
    t.in_order(t1)
    # 线索化二叉树
    t.threaded_node(t1)
    # 测试:以值为10 的结点来测试
    left_node = t5.left
    print()
    print("10 的前驱结点是:%d" % left_node.val)  # 3
    right_node = t5.right
    print("10 的后继结点是:%d" % right_node.val)  # 1
    print("线索化二叉树的中序遍历结果为:")
    t.threaded_in_order(t1)

后序线索化二叉树:

class Node(object):
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
        self.is_left_thread = False
        self.is_right_thread = False
        self.parent = None

    def add(self, node):
        if self.data > node.data:
            if self.left is None:
                self.left = node
                node.parent = self
            else:
                self.left.add(node)
        else:
            if self.right is None:
                self.right = node
                node.parent = self
            else:
                self.right.add(node)


class ThreadBinaryTree(object):

    def __init__(self):
        self.pre = None
        self.root = None

    def add(self, node):
        if self.root is None:
            self.root = node
        else:
            self.root.add(node)

    def post_order_thread(self, node):
        """
        后续线索化
        :return:
        """
        if node is None:
            return
        self.post_order_thread(node.left)
        self.post_order_thread(node.right)
        """
          1. left指向左子树或者指向前驱节点
          2. right指向右子树或者后继节点
        """
        if node.left is None:
            node.left = self.pre
            node.is_left_thread = True
        if self.pre is not None and self.pre.right is None:
            self.pre.right = node
            self.pre.is_right_thread = True; self.pre = node

        
    def threaded_post_order(self):
        """
        后续遍历
        :return:
        """
        temp = self.root
        # 定位到树最左端
        while temp.left is not None and temp.left.is_left_thread is False:
            temp = temp.left

        while temp is not None:
            # temp right 是后继节点
            if temp.is_right_thread:
                print(temp.data, end='->')
                self.pre = temp
                temp = temp.right
            else:
                # 后继节点之后的那一颗 子树需要特殊处理 必须拿到该子树的父节点然后继续
                if temp.right is self.pre:
                    print(temp.data, end='->')
                    self.pre = temp
                    temp = temp.parent
                else:
                    temp = temp.right
                    while temp.left is not None and temp.is_left_thread is False:
                        temp = temp.left


if __name__ == '__main__':
    binary_tree = ThreadBinaryTree()

    for i in range(1, 8):
        binary_tree.add(Node(i))

    binary_tree.post_order_thread(binary_tree.root)
    print('线索二叉树的后序遍历为:')
    binary_tree.threaded_post_order()

普通树转二叉树:

'''构造队列类'''
class Queue():
    # 初始化
    def __init__(self):
        self.array = []
    # 判断队列是否为空
    def QueueEmpty(self):
        return self.array == []
    # 入队,添加元素到队尾
    def EnQueue(self, item):
        self.array.append(item)
    # 出队,删除队头元素
    def DeQueue(self):
        return self.array.pop(0) # pop(0):删除第一个元素
    # 清空队列
    def clear(self):
        self.array = []
        print("清空队列完成!")
'''普通树结点'''
class CSNode():
    def __init__(self, data, children):
        self.data = data # 结点中携带的数据
        self.children = children # 当前结点的所有孩子集合
    
## 二叉树结点
class BiNode():
    def __init__(self):
        self.data = None # 结点中的数据
        self.left = None # 左结点
        self.right = None # 右结点

## 创建普通树转为二叉树的类
class Tree():
    # 初始化函数:普通树根结点,二叉树根结点,二叉树根结点数据
    def __init__(self, root):
        self.root = root # 普通树的根结点
        self.biroot = BiNode() # 初始化二叉树的根节点为空结点
        self.biroot.data = self.root.data # 把普通树根结点的数据赋予二叉树根结点的数据
    
    # 普通树转二叉树函数,结点之间的转换
    def transform(self):
        queue = Queue() # 创建队列,存储普通树的结点
        bqueue = Queue() # 创建队列,存储二叉树的结点
        queue.EnQueue(self.root) # 先把普通树根结点放入普通树队列中
        bqueue.EnQueue(self.biroot) # 把二叉树根结点放入二叉树队列中
        
        former = BiNode() # former结点变量主要控制兄弟结点转为孩子结点
        
        # 比如A结点有三个孩子BCD,上一步已经把A结点放入queue队列中,然后取出queue队列中的首元素,遍历孩子结点,然后将孩子结点放入队列中,再依次遍历孩子结点,直到没有结点遍历为止;
        # 每次都是先从队列中取结点,看是否有孩子结点,如果有,那就加进queue队列中,如果没有就不执行下面for循环,直到所有队列中的结点都取出完时,while循环停止!
        while not queue.QueueEmpty():
            node = queue.DeQueue() # 目前队列中普通树根结点
            bTreenode = bqueue.DeQueue() # 二叉树根结点
            
            # 根据当前结点的孩子数,来进行遍历,如果i==0,表示为左侧第一个孩子,则作为二叉树的左结点,如果有i>0的兄弟结点,则依次作为上一结点的右结点
            for i in range(len(node.children)):
                bnode = BiNode() # 创建空二叉树结点
                bnode.data = node.children[i].data # 新结点数据等于普通树孩子结点数据
                
                if i == 0: #i==0时,即把普通树的第一个孩子作为二叉树的左孩子
                    bTreenode.left = bnode
                else: # i>0时,后面的孩子结点作为前面结点的右孩子
                    former.right = bnode
                former = bnode # 将former结点表示为新结点所在位置

                queue.EnQueue(node.children[i]) # 将普通树中的结点放入普通树队列中
                bqueue.EnQueue(bnode) # 将新生成的二叉树结点放入二叉树队列中
                    
        return self.biroot # 当普通树所有结点都依次遍历完时,返回二叉树根结点,通过根结点依次遍历
    
    # 前序遍历
    def pre(self, node):
        #前序遍历、NLR、根左右
        if node == None:
            return
        #print(node.data)
        print("结点:{}, 左结点:{}, 右结点:{}".format(node.data, None if node.left == None else node.left.data, None if node.right == None else node.right.data))
        self.pre(node.left)
        self.pre(node.right)
''' 测试代码 '''
# 先创建普通树的结点
nodeG = CSNode('G', [])
nodeF = CSNode('F', [])
nodeE = CSNode('E', [])
nodeD = CSNode('D', [nodeG])
nodeC = CSNode('C', [])
nodeB = CSNode('B', [nodeE, nodeF])
nodeA = CSNode('A', [nodeB, nodeC, nodeD])

# 生成普通树转换为二叉树的一个类对象
bitree = Tree(nodeA)
root = bitree.transform() # 普通树转二叉树函数
bitree.pre(root) # 二叉树的前序遍历

森林转二叉树:(类比普通树转二叉树)

## 普通树结点
class CSNode():
    def __init__(self, data, children):
        self.data = data # 结点中携带的数据
        self.children = children # 当前结点的所有孩子集合
        
## 二叉树结点
class BiNode():
    def __init__(self):
        self.data = None # 结点中的数据
        self.left = None # 左结点
        self.right = None # 右结点

## 创建普通树转为二叉树的类
class Tree():
    # 初始化函数:普通树根结点,二叉树根结点,二叉树根结点数据
    def __init__(self, root):
        self.root = root # 普通树的根结点
        self.biroot = BiNode() # 初始化二叉树的根节点为空结点
        self.biroot.data = self.root.data # 把普通树根结点的数据赋予二叉树根结点的数据
    
    # 普通树转二叉树函数,结点之间的转换
    def transform(self):
        queue = Queue() # 创建队列,存储普通树的结点
        bqueue = Queue() # 创建队列,存储二叉树的结点
        queue.EnQueue(self.root) # 先把普通树根结点放入普通树队列中
        bqueue.EnQueue(self.biroot) # 把二叉树根结点放入二叉树队列中
        
        former = BiNode() # former结点变量主要控制兄弟结点转为孩子结点
        
        # 比如A结点有三个孩子BCD,上一步已经把A结点放入queue队列中,然后取出queue队列中的首元素,遍历孩子结点,然后将孩子结点放入队列中,再依次遍历孩子结点,直到没有结点遍历为止;
        # 每次都是先从队列中取结点,看是否有孩子结点,如果有,那就加进queue队列中,如果没有就不执行下面for循环,直到所有队列中的结点都取出完时,while循环停止!
        while not queue.QueueEmpty():
            node = queue.DeQueue() # 目前队列中普通树根结点
            bTreenode = bqueue.DeQueue() # 二叉树根结点
            
            # 根据当前结点的孩子数,来进行遍历,如果i==0,表示为左侧第一个孩子,则作为二叉树的左结点,如果有i>0的兄弟结点,则依次作为上一结点的右结点
            for i in range(len(node.children)):
                bnode = BiNode() # 创建空二叉树结点
                bnode.data = node.children[i].data # 新结点数据等于普通树孩子结点数据
                
                if i == 0: #i==0时,即把普通树的第一个孩子作为二叉树的左孩子
                    bTreenode.left = bnode
                else: # i>0时,后面的孩子结点作为前面结点的右孩子
                    former.right = bnode
                former = bnode # 将former结点表示为新结点所在位置

                queue.EnQueue(node.children[i]) # 将普通树中的结点放入普通树队列中
                bqueue.EnQueue(bnode) # 将新生成的二叉树结点放入二叉树队列中
                    
        return self.biroot # 当普通树所有结点都依次遍历完时,返回二叉树根结点,通过根结点依次遍历
    
    # 前序遍历
    def pre(self, node):
        #前序遍历、NLR、根左右
        if node == None:
            return
        print("结点:{}, 左结点:{}, 右结点:{}".format(node.data, None if node.left == None else node.left.data, None if node.right == None else node.right.data))
        self.pre(node.left)
        self.pre(node.right)
    
    # 森林转二叉树函数
    def forest_to_biTree(self, biroot_list):
        forest_root = self.root
        former = forest_root          
        for i in range(1, len(biroot_list)):
            former.right = biroot_list[i]
            former = biroot_list[i]          
        return forest_root # 当普通树所有结点都依次遍历完时,返回二叉树根结点,通过根结点依次遍历

二叉排序树:

"""定义结点"""
class BiTreeNode:
    def __init__(self,data):
        self.data = data
        self.lchild = None  # 左孩子
        self.rchild = None  # 右孩子
        self.parent = None

class BST:
    def __init__(self, li=None):
        self.root = None
        if li:
            for val in li:
                self.insert_no_rec(val)

    def insert(self, node, val):
        """递归插入"""
        if not node:
            node = BiTreeNode(val)
        elif val < node.data:
            node.lchild = self.insert(node.lchild, val)
            node.lchild.parent = node
        elif val > node.data:
            node.rchild = self.insert(node.rchild,val)
            node.rchild.parent = node
        return node

    def insert_no_rec(self, val):
        """非递归插入"""
        p = self.root
        if not p:     # 如果p为空,特殊处理
            self.root = BiTreeNode(val)
            return
        while True:
            if val < p.data:
                if p.lchild:
                    p = p.lchild
                else:    # 左孩子不存在
                    p.lchild = BiTreeNode(val)
                    p.lchild.parent = p
                    return
            elif val > p.data:
                if p.rchild:
                    p = p.rchild
                else:
                    p.rchild = BiTreeNode(val)
                    p.rchild.parent = p
            else:
                return
    
    def query(self, node, val):
        """递归查询"""
        if not node:   # 空树
            return None
        if node.data < val:
            return self.query(node.rchild, val)
        elif node.data > val:
            return self.query(node.lchild, val)
        else:
            return node

    def query_no_rec(self, val):
        """非递归查询"""
        p = self.root
        while p:
            if p.data < val:
                p = p.rchild
            elif p.data > val:
                p = p.lchild
            else:
                return p
        return None
    """
    1、删除的节点是叶子节点:直接删除,即没有孩子
    2、删除的节点只有一个孩子:将此节点的父亲与孩子连接,然后删除该节点
    3、删除的节点有两个孩子:将其右子树的最小节点(该节点最多有一个右孩子)删除,并替换当前节点
    """
    def __remove_node_1(self, node):
        # 情况1:node是叶子节点
        if not node.parent:  # 表明树里就一个节点
            self.root = None
        if node == node.parent.lchild:  # node是它父亲的左孩子
            node.parent.lchild = None
            # node.parent = None  因为断连了所以写不写这一句都可
        else:       #node是他父亲的右孩子
            node.parent.rchild = None

    def __remove_node_21(self, node):
        # 情况2.1:node只有一个左孩子
        if not node.parent:  # node为根节点
            self.root = node.lchild
            node.lchild.parent = None
        elif node == node.parent.lchild:    # node为它父亲的左节点
            node.parent.lchild = node.lchild   # 它父亲的左孩子等于它的左孩子
            node.lchild.parent = node.parent   # 它左孩子的父亲等于它的父亲
        else:           # node为它父亲的右节点
            node.parent.rchild  =node.lchild
            node.lchild.parent = node.parent

    def __remove_node_22(self, node):
        # 情况2.2:node只有一个右孩子
        if not node.parent:
            self.root = node.rchild
        elif node == node.parent.lchild:
            node.parent.lchild = node.rchild
            node.rchild.parent = node.parent
        else:
            node.parent.rchild = node.rchild
            node.rchild.parent = node.parent

    def delete(self,val):
        if self.root:    # 不是空树
            node = self.query_no_rec(val)   # 找到该节点
            if not node:  #删的元素不存在
                return False
            if not node.lchild and not node.rchild:   # 没有孩子
                self.__remove_node_1(node)
            elif not node.rchild:   # 只有一个左孩子
                self.__remove_node_21(node)
            elif not node.lchild:   # 只有一个右孩子
                self.__remove_node_22(node)
            else:
                """两个孩子都有"""
                min_node = node.rchild
                while min_node.lchild:
                    min_node = min_node.lchild
                node.data = min_node.data
                # 删除min_node
                if min_node.rchild:
                    self.__remove_node_22(min_node)
                else:
                    self.__remove_node_1(min_node)

    def pre_order(self, root):
        """前序遍历"""
        if root:  # 如果root不是空
            print(root.data, end=',')  # 访问根节点
            self.pre_order(root.lchild)  # 访问左子树
            self.pre_order(root.rchild)  # 访问右子树

    def in_order(self,root):
        """中序遍历"""
        if root:
            self.in_order(root.lchild)
            print(root.data, end=',')
            self.in_order(root.rchild)

    def post_order(self, root):
        """后序遍历"""
        if root:
            self.post_order(root.lchild)
            self.post_order(root.rchild)
            print(root.data, end=',')

    def level_order(self,root):
        """层次遍历"""
        queue = deque()
        queue.append(root)
        while len(queue) > 0:  # 只要队不空
            node = queue.popleft()  # 出队
            print(node.data, end=",")
            if node.lchild:
                queue.append(node.lchild)
            if node.rchild:
                queue.append(node.rchild)

平衡二叉树:

class Bbtree(): #平衡二叉树
    def __init__(self,item):
        self.item=item
        self.par=None
        self.l=None
        self.r=None
    def llink(self,other):
        self.l=other
        if other!=None:
            other.par=self
    def rlink(self,other):
        self.r=other
        if other!=None:
            other.par=self
    def plink(self,other): #向上连接父节点
        if other!=None:
            if self.item<other.item:
                other.llink(self)
            elif self.item>other.item:
                other.rlink(self)
            else:
                raise ValueError("节点值相同,无法连接")
        else:
            self.par=None
    def get_depth(self):
        if self.l==None:
            l_depth=0
        else:
            l_depth=self.l.get_depth()
        if self.r==None:
            r_depth=0
        else:
            r_depth=self.r.get_depth()
        return max(l_depth,r_depth)+1
    def get_bf(self): #获取平衡指数即左树深度-右树深度
        if self.l!=None:
            l_depth=self.l.get_depth()
        else:
            l_depth=0
        if self.r!=None:
            r_depth=self.r.get_depth()
        else:
            r_depth=0 
        return l_depth-r_depth           
    def show_mid(self,action=print):
        if self.l !=None:
            self.l.show_mid()
        action(self)
        if self.r !=None:
            self.r.show_mid()    
    def add_rec(self,value):#递归添加元素,与排序二叉树类似,增加了path作为返回值
        new=Bbtree(value)
        path_list=[self] #path_list用于记录经过的节点
        if value<self.item:
            path='L' #path记录每次添加元素时,从根节点到新增节点的路径,作为返回值,在每次递归时累加
            if self.l==None:
                self.llink(new)
            else:
                path_,path_list_=self.l.add_rec(value)
                path=path+path_
                path_list.extend(path_list_)
        elif value>self.item:
            path='R'
            if self.r==None:
                self.rlink(new)
            else:
                path_,path_list_=self.r.add_rec(value)
                path=path+path_
                path_list.extend(path_list_)
        else:
            pass
            path=''
            path_list=[]
        return path,path_list
    def add_nrec(self,value):
        new=Bbtree(value)
        tmp=self
        while value !=tmp.item:
            if value<tmp.item and tmp.l==None:
                tmp.llink(new)
                return
            elif value<tmp.item and tmp.l!=None:
                tmp=tmp.l
            elif value>tmp.item and tmp.r ==None:
                tmp.rlink(new)
                return
            else:
                tmp=tmp.r
    def search_rec(self,value):
        if value<self.item:
            if self.l==None:
                print("树中没有此值,最接近的为%d"%int(self.item))
                return False
            else:
                return self.l.search_rec(value)
        elif value>self.item:
            if self.r==None:
                print("树中没有此值,最接近的为%d"%int(self.item))
                return False
            else:
                return self.r.search_rec(value)
        else:
            return self
    def search_nrec(self,value):
        tmp=self
        while value !=tmp.item:
            if value<tmp.item and tmp.l==None:
                print("树中没有此值,最接近的为%d"%int(tmp.item))
                return False
            elif value<tmp.item and tmp.l!=None:
                tmp=tmp.l
            elif value>tmp.item and tmp.r ==None:
                print("树中没有此值,最接近的为%d"%int(tmp.item))
                return False
            else:
                tmp=tmp.r
        return tmp
    def __repr__(self):
        if self.l==None:
            litem=None
        else:
            litem=self.l.item
        if self.r==None:
            ritem=None
        else:
            ritem=self.r.item
        return '节点: '+str(self.item)+',左节点: '+str(litem)+', 右节点: '+str(ritem)+', 平衡因子: '+str(self.get_bf())
####四种类型的旋转
    def LL(self):
        A=self
        B=self.l
        tmp=A.par
        A.llink(B.r)
        B.rlink(A)
        B.plink(tmp)
    def RR(self):
        A=self
        B=self.r
        tmp=A.par
        A.rlink(B.l)
        B.llink(A)
        B.plink(tmp)
    def LR(self):
        A=self
        B=A.l
        C=B.r
        tmp=A.par
        A.llink(C.r)
        B.rlink(C.l)
        C.llink(B)
        C.rlink(A)
        C.plink(tmp)
    def RL(self):
        A=self
        B=A.r
        C=B.l
        tmp=A.par
        A.rlink(C.l)
        B.llink(C.r)
        C.rlink(B)
        C.llink(A)
        C.plink(tmp)        

def add_bbt(root,tree_list): #给定根节点,子节点序列,创建平衡二叉树   
    for i in tree_list:
        path,path_list=root.add_rec(i) #依次插入节点
        print('-'*25+'插入%d后'% i+'-'*25 )
        root.show_mid()
        for ix,j in enumerate(path_list):#对根节点到插入节点路径上的节点,调整平衡因子
            if abs(j.get_bf())>1: #如果节点失衡
                exec('j.%s()'%path[ix:ix+2]) #根据节点后的2次方向,确定旋转模式,进行旋转
                while root.par!=None: #调整root指针到旋转后的根节点
                    root=root.par
                print('-'*25+'%s旋转后'% path[:2]+'-'*25 )
                root.show_mid()
'''测试'''
A=Bbtree(5) #根节点
tree_list=[3,2,100,43,23,89,99,110,112]  #插入数据
add_bbt(A,tree_list)

哈夫曼树:

"""
【问题描述】使用贪心算法求解Huffman编码问题,具体来说就是,根据每个字符的出现频率,
            构造出字符的最优二进制表示,即前缀码。
            在程序开始说明部分,简要描述使用贪心算法求解Huffman编码问题的算法过程。
【输入形式】在屏幕上输入字符个数和每个字符的频率。
【输出形式】每个字符的Huffman编码。
"""
import numpy as np
class node:  # 结点类:结点,权值,左右子树
    def __init__(self, name=None, value=None):
        self._name = name
        self._value = value
        self._left = None
        self._right = None


class huff_man_tree:
    """
    根据哈夫曼算法,以叶子结点为基础,反向建立哈夫曼树:
    1、生成叶子结点;包括字符,权值
    2、对所有结点以权值进行从大到小排序
    3、取出最小的两个结点,即最后两个结点(并且删除两个结点)
    4、权值相加,生成一个结点
    5、在将这个生成的结点加入到结点中
    """
    def __init__(self, char_weights):
        self.a = [node(part[0], part[1]) for part in char_weights]  # 生成叶子结点
        while len(self.a) != 1:
            self.a.sort(key=lambda node: node._value, reverse=True)  # 以权值进行从大到小排序
            c = node(value=(self.a[-1]._value + self.a[-2]._value))
            c._left = self.a.pop(-1)
            c._right = self.a.pop(-1)
            self.a.append(c)
        self.root = self.a[0]
        self.b = np.zeros(self.root.__sizeof__(), dtype=np.int)  # self.b用于保存每个叶子节点的哈夫曼编码

    """递归的思想生成编码,从根结点开始,左子树为0,右子树为1,依次存储在以结点为键、编码为值的字典中。"""
    def set_code(self, tree, length, code):
        node = tree
        s = ""
        if not node:
            return
        elif node._name:
            for i in range(length):
                s = s + str(self.b[i])
            code[node._name] = s  # 哈夫曼编码字典
            return
        self.b[length] = 0
        self.set_code(node._left, length + 1, code)  # 递归左子树
        self.b[length] = 1
        self.set_code(node._right, length + 1, code)  # 递归右子树

    '''输出哈夫曼编码,对哈夫曼编码字典以键进行排序,依次输出哈夫曼编码'''
    def get_code(self):
        code = {}
        self.set_code(self.root, 0, code)
        code_name = sorted(code, key=lambda code: code[0])  # 哈夫曼编码字典以键进行排序
        for temp in code_name:
            print(temp, end=' ')
            print(code.get(temp))

def main():
    """
    【样例输入】
     6
     45 13 12 16 9 5
    """
    ch = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n']
    char_weights = []
    n = int(input())
    weight = [int(i) for i in input().split()]
    for i in range(n):
        char_weights.append((ch[i], weight[i]))  # 结点与权值
    """
    【样例输出】
    a 0
    b 101
    c 100
    d 111
    e 1101
    f 1100
    """
    tree = huff_man_tree(char_weights)
    tree.get_code()
    """
    【样例说明】
     输入:字符个数为6,a至f每个字符的频率分别为:45, 13, 12, 16, 9, 5。
     输出:每个字符对应的Huffman编码。
    """
if __name__ == '__main__':
    main()

 

posted @ 2022-04-26 19:10  hungry_J  阅读(16)  评论(0)    收藏  举报