哈夫曼樹是帶權值的樹節點結構,且目標節點都存儲在葉子節點上。下面使用Go實現哈夫曼樹
哈弗曼樹構建過程
- 將帶權值的節點進行排序,形成有序的鏈表。
- 取出鏈表頭兩個節點,權值相加形成新節點,並加入上述鏈表中重新排序,兩節點分別爲構建爲左右子樹,新創建的節點爲父節點。
- 重複步驟2直到鏈表節點爲1退出構造
哈夫曼節點定義
type huffmannode struct {
value interface{} //store the value of huffman tree node
weight uint32 //store the weight of node
}
節點實現鏈表的比較以及打印接口
func (hmn *huffManNode) Print() {
fmt.Printf("Value:%c Weight:%d\n", hmn.value, hmn.weight)
}
func (hmn *huffManNode) Cmp(h interface{}) int {
if hmn1, ok := h.(*huffManNode); ok {
if hmn.weight > hmn1.weight {
return 1
} else if hmn.weight == hmn1.weight {
return 0
} else {
return -1
}
}
return -2
}
實現過程中需要用到鏈表以及樹作爲輔助數據結構,鏈表定義可參考鏈表,樹結構可以參考二叉樹相關
創建哈夫曼樹實現如下
func CreatHuffman(keys map[interface{}]uint32) *jlalgorithm.BinaryTree {
var pRet *jlalgorithm.BinaryTree
var pList *jlalgorithm.LinkList
for key, value := range (keys) {
pList = jlalgorithm.OrderInsert(pList, jlalgorithm.NewLinkList(&huffManNode{key, value}))
}
jlalgorithm.Dump(pList)
for node := pList; node != nil; node = pList {
node1, _ := node.Value.(*huffManNode) //Get First Node Of The Order LinkList
if tmpTree1, ok := node1.value.(*jlalgorithm.BinaryTree); ok {
pRet = tmpTree1 //Judge The Node Is Tree Node
} else {
pRet = jlalgorithm.NewBinaryTree(node1)
}
if node.GetNext() != nil {
node2, _ := node.GetNext().Value.(*huffManNode) //Get The Second Node Of The Order LinkList
tmpTree := jlalgorithm.NewBinaryTree(nil)
tmpTree.AddLeft(pRet) //The Smaller Weight Node As The Left Child Node
if tmpTree2, ok := node2.value.(*jlalgorithm.BinaryTree); ok {
tmpTree.AddRight(tmpTree2)
} else {
tmpTree.AddRight(jlalgorithm.NewBinaryTree(node2))
}
//Create New Node Weight Is Sum Of The Two Node Weight
newnode := jlalgorithm.NewLinkList(&huffManNode{tmpTree, node1.weight + node2.weight})
pList = jlalgorithm.OrderInsert(node.GetNext().GetNext(), newnode)
} else {
break
}
}
//Handle Only One Node Of Huffman
if nil != pRet && nil != pRet.Value {
tmp := jlalgorithm.NewBinaryTree(nil)
tmp.AddLeft(pRet)
pRet = tmp
}
return pRet
}
獲取哈夫曼編碼
遍歷哈夫曼樹,左節點路徑爲0,右節點路徑爲1,找到目標節點所走的路徑即爲哈夫曼編碼。
func GetHuffmanCode(key interface{}, pRoot *jlalgorithm.BinaryTree) ([]byte, bool) {
if pRoot != nil {
ret := make([]byte, 0)
if pRoot.GetLeft() != nil {
if node, ok := pRoot.GetLeft().Value.(*huffManNode); ok {
if node.value == key {
return append(ret, 0), true
}
} else {
if result, ok := GetHuffmanCode(key, pRoot.GetLeft()); ok {
ret = append(ret, 0)
return append(ret, result...), true
}
}
}
if pRoot.GetRight() != nil {
if node, ok := pRoot.GetRight().Value.(*huffManNode); ok {
if node.value == key {
return append(ret, 1), true
}
} else {
if result, ok := GetHuffmanCode(key, pRoot.GetRight()); ok {
ret = append(ret, 1)
return append(ret, result...), true
}
}
}
}
return nil, false
}