【最優二叉樹】Huffman樹

Huffman樹,又稱作最優二叉樹,是一種用於信息編碼的數據結構。其通過對比各元素的頻率/數量,自底向頂構建一顆二叉樹,頻率越低的元素越在底部。在Huffman樹中,所有元素均爲葉子節點,而中間節點和根節點用於記錄兩顆孩子節點頻次和,從而避免編碼過程中可能存在的共用前綴的問題。

Huffman樹具備如下的基本功能和屬性:
(1)構建:基於元素頻率,自底向頂構建最優二叉樹;
(2)編碼:從root開始,設定左爲0,右爲1,沿着路徑進行編碼,可以證明這種編碼形式是信息量最優的編碼。

根據Huffman樹的基本屬性,不難想到用最小堆來實現。

1. 最小堆的實現

class PriorityQuene(object):
    """
    最小堆的定義
    :key  加入優先隊列的對象的排序key
    """
    def __init__(self, key):
        self.quene = []
        self.key = key

    def isEmpty(self):
        return len(self.quene)==0

    def size(self):
        return len(self.quene)

    def peek(self):
        return self.quene[0]

    def __repr__(self):
        return str([obj.__dict__.get(self.key) for obj in self.quene])

    def insert(self, obj):
        # key爲obj對象種用於排序的字段
        self.quene.append(obj)
        index = self.size() - 1
        while (index - 1)//2 >= 0 and self.quene[(index - 1)//2].__dict__.get(self.key) > obj.__dict__.get(self.key):
            self.quene[index], self.quene[(index - 1)//2] = self.quene[(index - 1)//2], self.quene[index]
            index = (index - 1)//2

    def pop(self):
        if self.isEmpty():
            return None
        if self.size() == 1:
            return self.quene.pop()
        else:
            item = self.quene[0]
            self.quene[0] = self.quene.pop()
            index = 0
            while 2 * index + 1 <= self.size() - 1:
                if 2 * index + 1 == self.size() - 1:         # 只有左節點
                    if self.quene[2 * index + 1].__dict__.get(self.key) < self.quene[index].__dict__.get(self.key):
                        self.quene[index], self.quene[2 * index + 1] = self.quene[2 * index + 1], self.quene[index]
                        index = 2 * index + 1
                    else:
                        break
                else:
                    if self.quene[2 * index + 1].__dict__.get(self.key) <= self.quene[2 * index + 2].__dict__.get(self.key) and self.quene[2 * index + 1].__dict__.get(self.key) < self.quene[index].__dict__.get(self.key):
                        self.quene[index], self.quene[2 * index + 1] = self.quene[2 * index + 1], self.quene[index]
                        index = 2 * index + 1

                    elif self.quene[2 * index + 2].__dict__.get(self.key) < self.quene[2 * index + 1].__dict__.get(self.key) and self.quene[2 * index + 2].__dict__.get(self.key) < self.quene[index].__dict__.get(self.key):
                        self.quene[index], self.quene[2 * index + 2] = self.quene[2 * index + 2], self.quene[index]
                        index = 2 * index + 2
                    else:
                        break
            return item

2. 構建節點對象和Huffman樹

class Node(object):
    """
    Huffman樹中的節點,包括:
    (1)葉子節點,即huffman需要編碼的字符
     (2) 中間節點:兩個葉子節點之和,或者
    """
    def __init__(self, frequency, value=None):
        self.frequency = frequency
        self.value = value          # 除了葉子節點保存字符信息,其它默認爲None,可以通過此判斷是否爲葉子節點
        self.parent = None
        self.leftChild = None
        self.rightChild = None

    def isLeftChild(self):
        if not self.parent:
            return False
        if self.parent.leftChild == self:
            return True
        else:
            return False

    def isRightChild(self):
        if not self.parent:
            return False
        if self.parent.rightChild == self:
            return True
        else:
            return False

    def getLeftChild(self):
        return self.leftChild

    def getRightChild(self):
        return self.rightChild

    def isLeaf(self):
        return self.value is not None


class HuffmanTree(object):
    def __init__(self):
        self.root = None
        self.nodeList = None
        self.encoding_dict = {}

    def buildTree(self, nodeList: list):            # 將Node對象放入優先隊列中,然後自底向上構建huffman數
        priQuene = PriorityQuene('frequency')       # 以Node對象的frequency屬性作爲排序依據
        self.nodeList = nodeList
        for node in self.nodeList:
            priQuene.insert(node)

        while priQuene.size() >= 2:
            node_left = priQuene.pop()           # type: Node
            node_right = priQuene.pop()          # type: Node
            node_parent = Node(node_left.frequency+node_right.frequency)
            node_left.parent = node_parent
            node_right.parent = node_parent
            node_parent.leftChild = node_left
            node_parent.rightChild = node_right
            priQuene.insert(node_parent)

        self.root = priQuene.pop()

    def encoding(self):
        # 爲整個huffman樹編碼
        # 左子樹編碼爲0, 右子樹編碼爲1
        for node in self.nodeList:
            node_coding = ''          # 初始化
            cur = node         # type: Node
            while cur != self.root:
                if cur.isLeftChild():
                    node_coding += '0'
                else:
                    node_coding += '1'
                cur = cur.parent
            self.encoding_dict.update({node.value: node_coding[::-1]})
        return self.encoding_dict

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章