實驗報告
科目:資料結構
姓名:朱凱迪
實驗日期:2010-12-29;
實驗名稱:
哈弗曼編碼 ;
一、實驗目的
1、熟悉哈夫曼樹的基本操作。 2、
掌握哈夫曼編碼的實現以及實際應用。 3、
加深對哈夫曼樹、哈夫曼編碼的理解,逐步培養解決實際問題的程式設計能力。
二、實驗環境
windows 7 + visual studio 2008
三、實驗內容和步驟
實驗內容:
利用哈夫曼編碼進行通訊可以大大提高通道利用率,縮短資訊傳輸時間,降低傳輸成本。但是,這要求傳送端通過乙個編碼系統對資料進行編碼,在接受端將傳來的資料進行解碼。試為這樣的資訊收發站寫乙個哈夫曼編碼/解碼系統。
本系統應實現以下功能:(功能1~3必做,4為選做,請課後自行完成)
(1)初始化:字符集(字母a~z,空格)共27個字元,以及其權值。建立哈夫曼樹。並建立各個字元的哈夫曼編碼。
(2)列印字符集的哈夫曼編碼。
(3)編碼:從終端讀入字串,實現該字串的編碼。
(4)解碼:實現剛才生成的哈夫曼編碼還原為字串。
實驗步驟:
我先按照實驗所說,實現了createht()函式和createhcode()函式,即建立哈弗曼樹函式以及建立哈弗曼編碼函式。權值以指導書中給的為準。哈弗曼樹以鏈式儲存方式進行儲存,每個結點有左兒子、右兒子的指標變數。在建立哈弗曼樹時,以資料結構「優先佇列」來儲存結點的佇列,並且最小權值的結點式中在隊首。而「優先佇列」則使用c++中的stl庫。在進行建立哈弗曼編碼的時候,採用了遞迴的方式,從根結點出發,一直查詢到葉結點,並記錄下路徑即哈弗曼編碼,以字串對映(map)儲存。哈弗曼編碼結果與熊劍聞同學進行對比,發現無異。
壓縮的演算法如下:先取第乙個字元,轉化為哈弗曼編碼二進位制,若不足八位,則取下乙個字元繼續編碼,直至達到八位,輸出第乙個壓縮後的字元,如此迴圈,直至所有字元全被壓縮。如a的哈弗曼編碼為1010,i的哈弗曼編碼為0100,則經壓縮後的」ia
」字串為(01001010)2
即十進位制的74即字元』j
』,這樣就實現了50%的壓縮。當然,這樣壓縮出來的結果的字元不一定是可見字元,因為字元ascii範圍為0~255。最後再輸出原文本的長度即可。而解壓縮的過程則反一下,先從檔案末尾讀取原文本長度,然後輸出原文本長度個字元。從第乙個字元的第一位開始拼湊,然後第二位,一直拼湊到能找到對應的哈弗曼編碼的字元為止,然後轉而尋找第二個字元的哈弗曼編碼。直至文字輸出完畢為止。
這次哈弗曼編碼實驗,我以《洛麗塔》一書作為實驗文字。原文大小為647,270 位元組,壓縮後的大小為370,847 位元組,壓縮率約為57.29%。
並且在解壓縮後與原文作對比,發現無損。至此,試驗完成。 四、
遇到問題及解決方案
開始在壓縮解壓處總出問題,壓縮過後的解壓過程總是會缺少一些字元甚至大篇幅缺失。在重新理清思路之後,將encode()和decode()函式刪除重新編寫一遍,以更精簡的**實現,結果對了。 五、
實驗感想
哈弗曼編碼是一種常用的編碼形式。甚至是winrar、zip、7z等壓縮軟體雖然不是是用哈弗曼編碼進行壓縮解壓,畢竟純哈弗曼編碼的壓縮率還是不足,但是至少它們多多少少都有點哈弗曼編碼的思想。所以這是一種很不錯的演算法。 六、
附件code:
/**
* @brief 哈夫曼編碼
* @author 朱凱迪
* @date 2010-11-30
*/#include
#include
#include
#include
using
namespace std;
/**
* @brief 哈弗曼結點
* 記錄了哈弗曼樹結點的資料、權重及左右兒子
*/struct htnode
/** 節點拷貝建構函式 */
htnode(const htnode &h)
/** 用於優先佇列比較的運算子過載 */
friend
bool operator < (const htnode &a, const htnode &b)
};
/** 哈弗曼樹葉子節點數、各葉子結點資料及權重 */
/** 權值從lolita**中抽樣取出 */
const
char ch = ;
const
int fnum = ;
const
int n = 91;
/** 優先佇列 */
priority_queuepq;
/** 哈弗曼編碼對映 */
mapchar> dcode;
map ecode;
/** 根節點以及總權重+邊長 */
htnode *root;
int sum = 0;
/** 初始化葉節點,並加入到優先佇列中 */
void init()
}
/** 建立哈夫曼樹 */
void createht()
if(!pq.empty())
}
/** 建立哈夫曼編碼 */
void createhtcode(htnode *p, string str)
createhtcode(p->lc, str + "0");
createhtcode(p->rc, str + "1");
}
/** 顯示哈夫曼編碼 */
void dispcode()
printf("平均長度:%.5lf/n", double(sum) / double(root->w));
}
/** 釋放哈夫曼樹 */
void release(htnode *p)
/** 輸出壓縮文 */
void putencode(file *fp, char *buf)
/** 判斷是否在字串內 */
bool instr(char c, const
char str)
/** 壓縮檔案 */
void encode()
of = fopen(ofn, "wb+");
if(!of)
/** 開始讀檔案 */
memset(buf, 0, sizeof(buf));
while(!feof(if))
}
cnt++;
}
cnt--;
if(0 != strlen(buf))
fwrite(&cnt, 4, 1, of);
fclose(if);
fclose(of);
printf("壓縮成功!壓縮率:%.2f%c/n", (((double)newcnt + 4.0f) / (double)cnt) * 100, '%');
}
/** 補0 */
void putzeros(char *buf)
}
/** 解壓縮 */
void decode()
file *of = fopen(ofn, "wb+");
if(!of)
int tot, cnt = 0;
fseek(if, -4l, seek_end);
fread(&tot, 4, 1, if);
fseek(if, 0l, seek_set);
memset(buf, 0, sizeof(buf));
while(true)
}
}
fclose(if);
fclose(of);
printf("解壓成功!檔名decode.txt。/n");
}
int main()
資料結構之哈弗曼樹與哈弗曼編碼
一.哈弗曼樹和哈弗曼編碼先知 哈弗曼樹是二叉樹中一種特殊的樹,也被稱為最優二叉樹。其通過某種規則 權值 來構造出一哈夫曼二叉樹,在這個二叉樹中,只有葉子節點才是有效的資料節點,其他的非葉子節點是為了構造出哈夫曼而引入的!哈夫曼編碼是通過哈夫曼樹進行的一種編碼,一般情況下,以字元 0 與 1 表示。編...
資料結構程設計 哈弗曼編碼
2011 06 12 16 34 70人閱讀收藏 舉報 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 include iostream using namespace std define max 21 typedef struct huffn...
資料結構 哈弗曼樹
code for fun created by dream whui 2015 2 8 include stdafx.h include using namespace std typedef struct 定義哈弗曼樹的結構 htnode,huffmantree typedef char huff...