基於哈夫曼編碼實現文件壓縮與解壓縮

基於哈夫曼編碼實現文件壓縮

是在學習數據結構(嚴蔚敏版)書中哈夫曼樹及其應用後對書中僞代碼的實現和完善,採用哈夫曼靜態編碼的方式,經過對數據進行兩遍掃描,第一次統計出現的字符頻次,進而構造哈夫曼樹,第二遍掃描數據根據獲得的哈夫曼樹對數據進行編碼。算法

對於其中的加密編碼只是簡單的將用戶輸入的密碼用特殊的標識位拼接成字符串加入須要統計的數據,能夠在擁有哈夫曼編碼表以及加密後的文本狀況下進行解密數據結構

哈夫曼樹

給定n個權值做爲n個葉子結點,構造一棵二叉樹,若帶權路徑長度達到最小,稱這樣的二叉樹爲最優二叉樹,也稱爲哈夫曼樹(Huffman Tree)。哈夫曼樹是帶權路徑長度最短的樹,權值較大的結點離根較近。學習

哈夫曼樹的構造過程

假設有n個權值,則構造出的哈夫曼樹有n個葉子結點。 n個權值分別設爲 w一、w二、…、wn,則哈夫曼樹的構造規則爲: (1)
將w一、w二、…,wn當作是有n 棵樹的森林(每棵樹僅有一個結點); (2)
在森林中選出兩個根結點的權值最小的樹合併,做爲一棵新樹的左、右子樹,且新樹的根結點權值爲其左、右子樹根結點權值之和;
(3)從森林中刪除選取的兩棵樹,並將新樹加入森林; (4)重複(2)、(3)步,直到森林中只剩一棵樹爲止,該樹即爲所求得的哈夫曼樹編碼

在構造哈夫曼樹時首先選擇權小的,這樣保證權大的離根較近,這種生成算法是一種典型的貪心法加密

哈夫曼編碼思想

爲了使壓縮後的數據文件儘量短,可採用不定長編碼。而爲了在對壓縮文件進行解碼時不產生二義性,確保正確解碼應該採用前綴編碼的形式(即要求一個字符的編碼不能是另外一個字符編碼的前綴)。而哈夫曼編碼是最優前綴編碼。code

例如:有一個數據序列ABACCDAA則編碼爲A(0),B(10),C(110),(D111),壓縮後爲010011011011100。字符串

部分實現代碼

//哈夫曼樹存儲表示 
typedef struct {
    int  weight;  //節點的權值 
    int parent,lchild,rchild;  //節點的雙親,左孩子,右孩子的下標 
} HTNode,*HuffmanTree;
 
//存儲數據掃瞄統計結果 
typedef struct {
    char* data;
    int* num;
    int length;
} TNode;
//存儲文件讀入哈夫曼編碼結果 
typedef struct {
    char *data;
    char** HM;
} Code;

//存儲哈夫曼編碼結果
typedef char** HuffmanCode;
//選取節點構造哈夫曼樹 
void Select(HuffmanTree &HT,int m,int& s1,int& s2) {
    int k,j,n,min=32767;
    for(k=1; k<=m; k++) {
        if(HT[k].parent==0)
            if(HT[k].weight<=min) {
                j=k;
                min=HT[k].weight;
            }
    }
    s1=j;
    HT[j].parent=1;
    min=32767;
    for(k=1; k<=m; k++) {
        if(HT[k].parent==0)
            if(HT[k].weight<=min) {
                n=k;
                min=HT[k].weight;
            }
    }
    s2=n;
}
//構造哈夫曼樹 
void CreateHuffmanTree (HuffmanTree &HT,TNode T,int length) {
    int m,i,s1,s2;
    //初始化 
    if(length<=1)
        return;
    m=2*length-1;
    HT=new HTNode[m+1];
    for(i=1; i<=m; ++i) {
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
    }
    for(i=1; i<=length; ++i)
        HT[i].weight=T.num[i-1];
    //經過n-1次的選擇,刪除,合併來建立哈夫曼樹 
    for(i=length+1; i<=m; i++) {
        Select(HT,i-1,s1,s2);
        HT[s1].parent=i;
        HT[s2].parent=i;
        HT[i].lchild=s1;
        HT[i].rchild=s2;
        HT[i].weight=HT[s1].weight+HT[s2].weight;
    }
}
//從葉子到根逆向求每一個字符的哈夫曼編碼,存儲在編碼表HC中 
void CreatHuffmanCode (HuffmanTree HT,HuffmanCode &HC,int n) {
    int i,f,c,start;
    HC=new char*[n+1];
    char* cd=new char[n];
    cd[n-1]='\0';
    for(i=1; i<=n; i++) {
        start=n-1;
        c=i;
        f=HT[i].parent;
        while(f!=0) {
            --start;
            if(HT[f].lchild==c)
                cd[start]='0';
            else
                cd[start]='1';
            c=f;
            f=HT[f].parent;
        }
        HC[i]=new char[n-start];
        strcpy(HC[i],&cd[start]);
    }
    delete cd;
}

有興趣能夠下載源碼查看https://pan.baidu.com/s/1skAP5lrget


參考 數據結構:C語言版/嚴蔚敏,李冬梅,吳偉民編源碼

相關文章
相關標籤/搜索