霍夫曼編碼(Huffman Coding),又譯為哈夫曼編碼、赫夫曼編碼,是一種用於無損資料壓縮 演算法。由大衛·霍夫曼在 1952 年發明。

在電腦資料處理中,霍夫曼編碼使用變長編碼表對源符號(如檔案中的一個字母)進行編碼。 例如,在英文中,e 的出現機率最高,而 z 的出現機率則最低。當利用霍夫曼編碼對一篇英文 進行壓縮時,e 極有可能用一個位元來表示,而 z 則可能花去 25 個位元(不是 26)。用普通 的表示方法時,每個英文字母均占用一個字元組,即 8 個位元。二者相比,e 使用了一般編 碼的1/8的長度, z則使用了3倍多。倘若我們能對於英文中各個字母出現機率較準確的估算, 就可以大幅度提高無失真壓縮的比例。 霍夫曼編碼(Huffman Coding)要先建立霍夫曼樹(Huffman Tree): 建立霍夫曼樹(Huffman Tree)步驟: (一) 針對相異字元, 統計其出現的次數 :

(二) 為每個字元建立一顆只有一節點的樹, 每棵樹的根節點之關鍵值(紅色字)為其字元出現的 次數. 


(三) 找出根節點關鍵值(出現次數)最小的兩顆樹。 


(四) 產生一個新的根節點,並將找到的兩棵樹分別當作此新的根節點之左右子樹(節點關鍵值 大的放左樹,關鍵值小的放右樹或是節點關鍵值小的放左樹,關鍵值大的放右樹),而根節點 的關鍵值為左右子樹節點之關鍵值(紅色字)的和. 


(五) 重複步驟 (三) 與 (四),直至全部節點合併為一棵樹。 


( 三) 找出根節點關鍵值(出現次數)最小的兩顆樹13,1(三) 找出根節點關鍵值(出現次數)最小的兩顆樹8,11。


(三)找出根節點關鍵值(出現次數)最小的兩顆樹19,19。 二個關鍵值一樣,可以安照排序先後秩序(三) 找出根節點關鍵值(出現次數)最小的兩顆樹28,38 

輸入說明: 第一列的數字 n 代表有幾筆資料要測試, ,第二列起為測試資料,之後每列為每組 測試資料,每組測試資料至少有2個正整數最多有26個正整數,正整數數字 , 。 各個數字間以“,”隔開,分別代表各字元的出現的次數。每組資料都有 M 個相異數字 ( ) ,讓你去建立霍夫曼樹(Huffman Tree)。會避免 3,3,8,8 這樣輸出結果不唯一的 測試資料。

輸出說明: 在測試資料中所建建立霍夫曼樹(Huffman Tree),完成霍夫曼編碼(Huffman Code)及計算霍夫 曼編碼(Huffman Code)位元數(長度),這組測試資料輸出一列,各個數字間以“,”隔開,分別代 表各字元的霍夫曼編碼(Huffman Code)位元數(長度)。

輸入檔案 1:【檔名:in1.txt】
2
 2,3,6,8,13,15,19
 4,8,5

輸入檔案 2:【檔名:in2.txt】
 3
26,25,20,15,10,5
4,3,5,6
2,1

輸出範例:【檔名:out.txt】
5,5,4,3,2,2,2
2,1,2

2,2,2,3,4,4
2,2,2,2
1,1

程式碼解說:
以下為全域變數
Structure bitree   '結構
        Dim p As Integer  '樹的父
        Dim leftch As Integer'樹的左子
        Dim rightch As Integer'樹的右子
        Dim data As Integer '值
    End Structure
    Dim n = 0
    Dim a() As bitree '陣列裝樹的結構
    Dim anst = ""

Dim s = "26,25,20,15,10,5" '字元出現次數
Dim starray1 = s.Split(",")
 n = UBound(starray1)
        Dim starray(n) As Integer
        For i = 0 To n 'UBound(starray)
            starray(i) = Int(starray1(i))'換成整數
        Next
        Array.Sort(starray)'排序

Dim f = True
        ReDim a(n) 'As bitree
     
        Dim m = 0
        Dim s1 = 0
        Dim s2 = 1
排序後取最後2位放入結構陣列最小的
        While f
            If s2 <= n Then
                a(m).leftch = starray(s2) '大的放左
                a(m).rightch = starray(s1) '小的放右
                a(m).p = Int(starray(s1)) + Int(starray(s2)) '父為兩者值
                starray(s2) = Int(starray(s1)) + Int(starray(s2))放入陣列
                starray(s1) = 0'已放入結構的歸0
                Array.Sort(starray)'重新排序
                s1 += 1'往後取
                s2 += 1
                m += 1'下一個結構陣列
            Else
                f = False
            End If
        End While
跑完迴圈全部放入結構陣列了


遞迴副程式
 Sub findlayers(ByVal target, ByVal m, ByVal edge, ByVal n2) 'target 是要找的值,m 為根 n2是陣列個數
        Dim m1 = m
        Dim n1 = n2
        ' anst = edge
        If target <> m1 And n1 >= 0 Then'没找到同時没超過陣列數目
            For i = n1 To 0 Step -1'結構陣列中去找`
                If a(i).p = m Then'找到根的結構往下
             
                     If target = a(i).leftch Then
                        anst = edge & "0" '找到值了因往左所以路徑加0且停止
                    Else'没找到継續往下
                        findlayers(target, a(i).leftch, edge & "0", n1) '左子成為下一個要找根 路徑多一0
                    End If

                    If target = a(i).rightch Then'找到值了因往右所以路徑加1且停止
                        anst = edge & "1"
                    Else
                        findlayers(target, a(i).rightch, edge & "1", n1)'右子成為下一個要找根 路徑多一1
                    End If

                End If

            Next
        End If

    End Sub


 Dim root = a(n - 1).p  最上層的父為止樹的根
        Dim codest = ""
        Dim ans = ""
        Dim lengthcode = 0

        For i = 0 To n '每一數往下找
            findlayers(starray1(i), root, "", n - 1)'副程式遞迴
            codest = codest & anst & "/" 編碼(01等)
            lengthcode = Len(anst)'有幾個路徑即為位元數(長度)。
            ans = ans & lengthcode & "/"
            anst = ""

        Next
        MsgBox(codest)
        MsgBox(ans)

影音解說








留言