任意ASCII碼格式信息的huffman tree壓縮(編碼)和解壓(譯碼)

任意ASCII碼格式信息的huffman tree壓縮(編碼)和解壓(譯碼)

作者:牛老師,華清遠見嵌入式學院講師。

計算機實踐中發現,大多數信息的表達都存在着一定的冗餘度,有效的降低這種冗餘度可以使我們用更小的空間存儲更大的數據量,同時在有限的通信帶寬的情況下,可以傳輸更多的信息,等等……。那用什麼辦法可以降低這種冗餘度,這裏我們學習其中的一種huffman treee壓縮(編碼)和解壓(譯碼)方法。

huffman tree的壓縮和解壓的過程如下:

1、描述

對於任意的ASCII格式的信息aba$a@ba*a$a,先統計它們的出現頻率a6,b2,$2,*1,@1,然後分別用不等長的01串來編碼它們,如a1,b00,$011,*0100,@0101,最後用01串替換原來的信息,得到100101110101001010010111,並按二進制位組合,這樣就可以得到壓縮後的文件。

相對應,解壓時必須知道編碼a1,b00,$011,*0100,@0101,然後根據100101110101001010010111一步步解壓得到aba$a@ba*a$a原始信息。

2、分析

爲了解壓成功,首先必須保證任何已經編碼的單個字符不能是其他字符編碼的前綴,也就是說用1編碼a以後,其他字符編碼不能以1開頭。爲了實現壓縮的最小,同時要保證出現頻率最高的字符編碼最短,頻率最低的編碼最長。

3、方法

通過描述和分析,我們明白這種方法是可以實現壓縮文件的,用什麼辦法可以實現這種方法呢?使用最優二叉樹也就是huffman tree可以實現上面的方法,步驟如下:

1) 將a6,b2,$2,*1,@1按照頻率值從小到大有序入隊,出隊兩個元素,分別以它們爲左右子樹,建立二叉樹,並將它們出現次數之和作爲根節點,把根節點有序入隊。

@1      *1      $2      b2      a6

    2           $2       b2    a6
      / \
    @1     *1

2) 然後重複1步驟直到隊中只剩下一個節點,該節點就是所求huffman tree的根節點,最後按照左0,右1進行編碼a1,b00,$011,*0100,@0101。

b2      4      a6
          / \
        2      $2
      / \
    @1      *1

    6      a6
      / \
    b2      4
          / \
        2      $2
      / \
    @1      *1

         12
          0/  1\
         6        a6
     0/  1\      1
    b2        4
    00    0/  1\
         2        $2
     0/  1\     011
    *1       @1
    0100     0101

4、步驟
        第一步:統計aba$a@ba*a$a字符出現的頻率,a6,b2,$2,*1,@1。
        第二步:去除重複的字符ab$@*。
        第三步:創建huffman tree,對ab$@*進行編碼a1,b00,$011,*0100,@0101。
        第四步:aba$a@ba*a$a根據編碼a1,b00,$011,*0100,@0101壓縮爲10010111010
                        1001010010111。
        第五步:100101110101001010010111根據huffman tree解壓爲aba$a@ba*a$a。

5、實現

treehuffman.c

1. #include <stdio.h>
        2. #include <stdlib.h>
        3. #include <string.h>
        4. #include "treehuffman.h"
        5. #include "../queue/queuelink.h"
        6.
        7. treehuffman *treecreate(char *s)
        8. {
        9.           int w[256] = {};
        10.         int i;
        11.         char c[256] = {}, *pc = c;
        12.         queuelink *q = queuecreate();
        13.        queuedata temp;
        14.
        15.         // 第一步
        16.         while(*s != '\0')
        17.         {
        18.                 w[(int)*s++]++;
        19.         }
        20.
        21.         // 第二步
        22.         for(i=0; i<256; i++)
        23.         {
        24.                if(w[i] != 0)
        25.                 {
        26.                         *pc++ = i;
        27.                 }
        28.         }
        29.
        30.         // 第三步
        31.         pc = c;
        32.         while(*pc != '\0')
        33.         {
        34.                 temp = (treehuffman *)malloc(sizeof(treehuffman));
        35.
        36.                 temp->c = *pc;
        37.                 temp->w = w[(int)*pc++];
        38.                 temp->code[0] = '\0';
        39.                 temp->lchild = temp->rchild = NULL;
        40.
        41.                 queueenterorder(q, temp);
        42.         }
        43.
        44.         while(q->front->next != q->rear)
        45.         {
        46.                 temp = (treehuffman *)malloc(sizeof(treehuffman));
        47.
        48.                temp->code[0] = '\0';
        49.                 temp->lchild = queuedelete(q);
        50.                 temp->rchild = queuedelete(q);
        51.                 temp->w = temp->lchild->w+temp->rchild->w;
        52.
        53.                queueenterorder(q, temp);
        54.        }
        55.
        56.         return queuedelete(q);
        57. }
        58.
        59. // 第四步
        60. char *treecompress(treehuffman *t, char *s, char *compressed)
        61. {
        62.         queuelink *q = queuecreate();
        63.         queuedata temp;
        64.         char *code[256];
        65.
        66.         queueenter(q, t);
        67.
        68.         while(queueempty(q) == 0)
        69.        {
        70.                 temp = queuedelete(q);
        71.
        72.                 if(temp->lchild==NULL && temp->rchild==NULL)
        73.                 {
        74.                         code[(int)temp->c] = temp->code;
        75.                         printf("%c(%d) : %s\n", temp->c, temp->w, temp->code);
        76.                 }
        77.
        78.                 if(temp->lchild != NULL)
        79.                 {
        80.                         strcpy(temp->lchild->code, temp->code);
        81.                         strcat(temp->lchild->code, "0");
        82.                         queueenter(q, temp->lchild);
        83.                 }
        84.
        85.                 if(temp->rchild != NULL)
        86.                 {
        87.                        strcpy(temp->rchild->code, temp->code);
        88.                        strcat(temp->rchild->code, "1");
        89.                         queueenter(q, temp->rchild);
        90.                 }
        91.         }
        92.
        93.        while(*s != '\0')
        94.         {
        95.                strcat(compressed, code[(int)*s++]);
        96.         }
        97.
        98.         return compressed;
        99. }
        100.
        101. // 第五步
        102. char *treeuncompress(treehuffman *t, char *compressed, char *compress)
        103. {
        104.        char *p = compress;
        105.        treehuffman *temp = t;
        106.
        107.        while(*compressed != '\0')
        108.        {
        109.                if(*compressed++ == '0')
        110.                {
        111.                        temp = temp->lchild;
        112.                }
        113.                else
        114.                {
        115.                        temp = temp->rchild;
        116.                }
        117.
        118.                if(temp->lchild==NULL && temp->rchild==NULL)
        119.                {
        120.                        *compress++ = temp->c;
        121.                        temp = t;
        122.                }
        123.        }
        124.
        125.        return p;
        126. }

1treehuffman.h

127. #ifndef __TREEHUFFMAN_H__
        128. #define __TREEHUFFMAN_H__
        129.
        130. typedef char treedata;
        131.
        132. typedef struct tree
        133. {
        134.        treedata c;
        135.        int w;
        136.        char code[16];
        137.        struct tree *lchild, *rchild;
        138. }treehuffman;
        139.
        140. extern treehuffman *treecreate(char *s);
        141. extern char *treecompress(treehuffman *t, char *s, char *compressed);
        142. extern char *treeuncompress(treehuffman *t, char *compressed, char *compress);
        143.
        144. #endif

注意:對於a6,b2,$2,*1,@1來說,結果可能有幾種,可能是a1,b00,$011,*0100,@0101,也可以是a1,$00,b011,@0100,*0101。這是因爲統計的頻率中有相等的,所以在有序入隊時他們可能是左子樹,也可能是右子樹,所以出來的結果可能與程序本身的處理有關,不過不影響最終的壓縮率。

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