哈夫曼树可视化

import matplotlib.pyplot as plt


class Tree:
    def __init__(self, weight=None, left=None, right=None):
        self.weight = weight
        self.left = left
        self.right = right
        self.is_red = False

    def get_height(self):  # 返回树高度,未优化算法应该比较慢
        layers = [self]
        layer_count = 0
        while layers:
            layer_count += 1
            new_list = []
            for node in layers:
                if node.left:
                    new_list.append(node.left)
                if node.right:
                    new_list.append(node.right)
            layers = new_list
        return layer_count

    def visualize(self, axis='off'):
        ''' 可视化树结构

            基本算法: 将树状结构映射到二维矩阵中,
            如果节点左右下方有节点则把该节点加入到矩阵中的坐标中,
            如节点(x,y)左下方有节点则把节点放入(x+offset,y+1)
            offset为x坐标偏移量,
            offset = 2**(len(matrix)-y-2)
        '''
        FONT_SIZE = 16
        NODE_SIZE_SCALE = 1.5
        figure, axes = plt.subplots(figsize=(8, 6), dpi=80)
        height = self.get_height()
        width_ = 2 ** (height - 1)
        width = 2 * width_ + 1
        matrix = [[[] for x in range(width)] for y in range(height)]

        matrix[0][width_] = self  # put head in the middle position

        for y in range(len(matrix)):
            for x in range(len(matrix[y])):
                node = matrix[y][x]
                if node:
                    x1, y1 = (1 / width) * (x + 0.5), 1 - (1 / height) * y - 0.2
                    axes.text(x1, y1, str(node.weight), color='white', fontsize=FONT_SIZE)
                    offset = 2 ** (len(matrix) - y - 2)

                    if node.left:
                        matrix[y + 1][x - offset] = node.left
                        x2, y2 = (1 / width) * (x - offset + 0.5), 1 - (1 / height) * (y + 1) - 0.2
                        line = mlines.Line2D([x1, x2], [y1, y2], zorder=-1)
                        axes.add_line(line)
                    if node.right:
                        matrix[y + 1][x + offset] = node.right
                        x2, y2 = (1 / width) * (x + offset + 0.5), 1 - (1 / height) * (y + 1) - 0.2
                        line = mlines.Line2D([x1, x2], [y1, y2], zorder=-1)
                        axes.add_line(line)
                    cc = plt.Circle(((1 / width) * (x + 0.5), 1 - (1 / height) * y - 0.2),
                                    1 / width / 2 * NODE_SIZE_SCALE,
                                    color=('r' if node.is_red else 'black'))
                    axes.set_aspect(1)
                    axes.add_artist(cc, )

        plt.axis(axis)
        plt.show()


class HuffmanTree:
    """哈夫曼树(huffmanTree)

    构建方法:
        将几点根据权重大小放到最小堆中,先从做小堆中取出两个最小元素,构成一棵树,根节点权重为两子树的和。然后将根节点插入堆中,依次上边操作,
        共计操作数据长度-1次,此时堆中只有一个元素,就是哈夫曼树的根节点。WPL等于根节点的权重值。
    """
    def __init__(self, element: list):
        self._element = element
        self._size = len(element) + 1
        self._used = 0
        self._case = [None for _ in range(self._size)]

    def _is_full(self):
        return self._used > self._size

    def insert(self, root: Tree):
        """往堆中插入元素"""
        if self._is_full():
            return 'is full'

        self._used += 1
        add_node = self._used
        father = self._used // 2
        while father:
            if root.weight > self._case[father].weight:
                break
            self._case[add_node] = self._case[father]
            add_node = father
            father //= 2

        self._case[add_node] = root

    def delete(self):
        """从堆中删除元素"""
        if self._used == 0:
            return 'is empty'

        root = 1
        res = self._case[root]
        # node = self._used
        while True:
            left_son = root * 2
            right_son = left_son + 1

            if left_son < self._used and self._case[left_son].weight <= self._case[right_son].weight and self._case[
                left_son].weight < \
                    self._case[self._used].weight:
                self._case[root] = self._case[left_son]
                root = left_son
            elif right_son < self._used and self._case[right_son].weight <= self._case[left_son].weight and self._case[
                right_son].weight < \
                    self._case[self._used].weight:
                self._case[root] = self._case[right_son]
                root = right_son
            else:
                break

        self._case[root] = self._case[self._used]
        self._case[self._used] = None
        self._used -= 1
        return res

    def create(self):
        """构建哈夫曼树"""
        for i in self._element:
            tree = Tree(i)
            self.insert(tree)

        for _ in range(self._size - 2):
            left = self.delete()
            right = self.delete()
            tree = Tree(left.weight + right.weight, left, right)
            self.insert(tree)

        tree = self.delete()
        return tree


if __name__ == '__main__':
    # heap = Heap()
    a = [3, 1, 4, 5, 6]
    huff = HuffmanTree(a)
    r = huff.create()
    # t = Tree()
    r.visualize()  # 可视化树结构

效果展示
image