利用huffman編碼實現壓縮檔案
阿新 • • 發佈:2019-01-06
哈夫曼是一種常用的壓縮方法。是1952年為文字檔案建立的,其基本原理是頻繁使用的資料用較短的程式碼代替,很少使用的資料用較長的程式碼代替,每個資料的程式碼各不相同。這些程式碼都是二進位制碼,且碼的長度是可變的。如: 有一個原始資料序列,ABACCDAA則編碼為A(0),B(10),C(110),(D111),壓縮後為010011011011100。
產生霍夫曼編碼需要對原始資料掃描兩遍,第一遍掃描要精確地統計出原始資料中的每個值出現的頻率,第二遍是建立霍夫曼樹並進行編碼,由於需要建立二叉樹並遍歷二叉樹生成編碼,因此資料壓縮和還原速度都較慢,但簡單有效,因而得到廣泛的應用。 哈夫曼演算法在改變任何符號二進位制編碼引起少量密集表現方面是最佳的。然而,它並不處理符號的順序和重複或序號的序列。
哈夫曼壓縮,首先用ASCII值初始化511個哈夫曼節點,然後,計算在輸入緩衝區資料中,每個ASCII碼出現的頻率。然後,根據頻率進行排序,現在,構造哈夫曼樹,獲取每個ASCII碼對應的位序列,構造哈夫曼樹,將所有的節點放到一個佇列中,用一個節點替換兩個頻率最低的節點,新節點的頻率就是這兩個節點的頻率之和。這樣,新節點就是兩個被替換節點的父節點了。如此迴圈,直到佇列中只剩一個節點(樹根)。壓縮的最後一步是將每個ASCII編碼寫入輸出緩衝區中 哈夫曼解壓縮,將輸入緩衝區中的每個編碼用對應的ASCII碼逐個替換就可以了。只要記住,這裡的輸入緩衝區是一個包含每個ASCII值的編碼的位流。因此,為了用ASCII值替換編碼,我們必須用位流搜尋哈夫曼樹,直到發現一個葉節點,然後將它的ASCII值新增到輸出緩衝區中。
- /*****************************************************************/
- /*****************************************************************/
- /**程式: compress.c **/
- /**功能: 壓縮與解壓縮單個檔案 **/
-
/**詳情: 利用霍夫曼演算法生成輸入檔案的霍夫曼編碼,並轉換成二進位制**/
- /** 位元組流輸出從而達到壓縮的效果;解壓縮則是從壓縮檔案中讀**/
- /** 入霍夫曼樹資訊,從而還原為原編碼,達到解壓縮的目的。 **/
- /** 壓縮檔案結構 **/
- /** 偏移量 儲存資訊型別 **/
- /** 0~3 檔案頭標誌 **/
- /** 4 原始檔名長度:n_s **/
- /** 5~4+n_s 檔名 **/
- /** 5+n_s~8+n_s 原始檔長度 **/
- /** 9+n_s~1028+n_s huffman樹非葉子節點孩子資訊 **/
- /** 1029+n_s~FILE_END 原始檔的huffman二級制編碼資訊 **/
- /**環境: AM2_4000+ & Windows_Server_2008 & VC++_2008 **/
- /**其他: davelv @ 2008-12-18 **/
- /*****************************************************************/
- /*****************************************************************/
- ////////////////////////////////////////////////////////////////////
- //// 標頭檔案、自定義型別、預定義巨集常量 ////
- ////////////////////////////////////////////////////////////////////
- #define _CRT_SECURE_NO_DEPRECATE//VC2005或更新的編譯器不顯示I/O安全警告
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- typedef unsigned intUINT;
- typedef unsigned charUCHAR;
- typedef unsigned shortUSHORT;
- typedefstruct node
- {
- long w;//權
- short p,l,r;//父親,左孩子,右孩子
- }htnode,*htnp;//霍夫曼樹的結點
- typedefstruct huffman_code
- {
- UCHAR len;//長度
- UCHAR *codestr;//字串
- }hufcode;//字元版本的霍夫曼編碼
- #define OK 1
- #define ERROR -1
- #define UNUSE -1
- #define ARGS_ERR -2//引數錯誤
- #define FILE_ERR -3//檔案錯誤
- #define HEAD_ERR -4//頭標錯誤
- #define MALLOC_ERR -5//記憶體分配錯誤
- #define HUFTREE_ERR -6//霍夫曼樹錯誤
- #define HUFCODE_ERR -7//霍夫曼編碼錯誤
- #define CHAR_BITS 8//一個字元中的位數
- #define INT_BITS 32//一個整型中的位數
- #define CODE_SIZE 256//霍夫曼編碼個數
- #define CACHE_SIZE 256//I/O快取大小
- #define UINT_SIZE sizeof(UINT)
- #define UCHAR_SIZE sizeof(UCHAR)
- #define USHORT_SIZE sizeof(USHORT)
- #define ZIP_HEAD 0xFFFFFFFF//壓縮檔案頭標
- #define MAX_NAME_LEN 512
- ////////////////////////////////////////////////////////////////////
- //// 函式宣告 ////
- ////////////////////////////////////////////////////////////////////
- //壓縮相關函式
- UCHAR chars_to_bits(constUCHAR chars[CHAR_BITS]);//將一個字元陣列轉換成二進位制數字@ write_compress_file()
- int search_set(htnp ht,int n);//查詢當前最小權值的霍夫曼樹節點並置為佔用@create_huffmantree()
- int create_huffmantree(long w[],int n,htnode ht[]);//生成霍夫曼樹@compress()
- int encode_huffmantree(htnp htp,int n,hufcode hc[]);//生成霍夫曼編碼@compress()
- long calc_data_frequency(FILE *in,long frequency[]);//計算每個不同位元組的頻率以及所有的位元組數@compress()
- int compress(char *source_filename,char *obj_filename);//處理壓縮檔案的流程@process_args()
- int c_initial_files(char *source_filename,FILE **inp,char *obj_filename,FILE **outp);//為處理壓縮流程初始化檔案@compress()
- int write_compress_file(FILE *in,FILE *out,htnp ht,hufcode hc[],char* source_filename,long source_filesize);//寫壓縮檔案@compress()
- //解壓縮相關函式
- void get_mini_huffmantree(FILE* in,short mini_ht[][2]);//從待解壓縮檔案中得到一個小型的huffman樹@decompress()
- int decompress(char *source_filename,char *obj_filename);//處理解壓縮檔案的流程@process_args()
- int d_initial_files(char *source_filename,FILE **inp,char *obj_filename,FILE **outp);//為處理解壓縮流程初始化檔案@decompress()
- int write_decompress_file(FILE *in,FILE* out,short mini_ht[][2],long bits_pos,long obj_filesize);//寫解壓縮檔案@decompress()
- //輔助函式
- void print_help();//在螢幕上顯示幫助@process_args(),main()
- void process_error(int error_code);//處理函式中返回的錯誤程式碼@process_args(),main()
- void process_args(char *first,char*second,char*third);//處理命令列引數@main()
- char *create_default_obj_filename(char *source_filename,char* obj_filename);//生成一個預設的檔名@c_initial_files()
- ////////////////////////////////////////////////////////////////////
- //// 壓縮相關函式 ////
- ////////////////////////////////////////////////////////////////////
- /****************************************************************/
- /*函式: c_initial_files() */
- /*功能: 初始化並開啟壓縮功能所需所有檔案 */
- /*引數: char *source_filename 原始檔名字串 */
- /* FILE **inp 指向輸入檔案指標的指標 */