6: Cây Huffman điền đầy đủ thành phần (vi dụ 2)

Một phần của tài liệu Tiếp cận mã huffman theo tần suất và ứng dụng (Trang 37 - 75)

Từ mã của các kí tự đƣợc sinh ra từ cây cuối cùng này, đƣợc thể hiện trong bảng sau. 0 đƣợc sử dụng cho cạnh trái, 1 đƣợc sử dụng cho cạnh phải.

Kí tự Từ mã Độ dài

n 10 4

g 00 3

Số hóa bởi Trung tâm Học liệu - ĐHTN http://www.lrc.tnu.edu.vn/ h 010 2 t 1111 2 i 0111 1 c 1110 1 e 0111 1

Nhƣ vậy với mỗi ký hiệu đƣợc lƣu trữ bình thƣờng là 8 bit khi đó với chuỗi đầu vào là “congnghethongtin” thì ta phải mất 8 x 16 = 128 bit trong khi đó sử dụng phƣơng pháp nén Huffman “congnghethongtin” ->

1110110100010000100111111101011010001111011110= 6 bit

2.3.5. Giải mã thuật toán Huffman

Giải mã từng ký tự dựa vào việc duyệt cây từ gốc cho tới tận lá:

- Đọc lần lƣợt từng bit một của thông điệp đã bị mã hóa, và tiến hành duyệt từ gốc cây xuống. Nếu đọc đƣợc bit 1 thì rẽ nhánh bên phải, ngƣợc lại rẽ nhánh bên trái.

- Tiến hành vừa đọc vừa duyệt cho tới khi thấy lá, vậy là giải đƣợc mã cho một ký tự, quay trở lại gốc cây chờ chờ duyệt tiếp.

- Quá trình đọc thông điệp và duyệt cây đƣợc tiếp tục cho tới khi hết thông điệp.

Ví dụ: Giải mã “1110110” với cây Huffman ở hình 2.5

Duyệt từ gốc cây,đọc đƣợc bit 1, rẽ bên nhánh phải và gặp nút 9 (chƣa phải lá), đọc tiếp bit 1, rẽ nhánh phải và gặp nút 5 (chƣa phải là lá), đọc tiếp bit 1, rẽ nhánh bên phải gặp nút 3 (chƣa phải là lá), đọc tiếp bit 0 rẽ nhánh trái, gặp lá c, giải đƣợc chữ c. Trở về gốc cây, tƣơng tự đọc đƣợc bit 1 rẽ bên nhánh phải gặp nút 9 (chƣa phải lá), đọc tiếp bit 1, rẽ nhánh phải và gặp nút 5 (chƣa phải là lá) đọc tiếp bit 0 rẽ nhánh trái gặp lá o giải đƣợc chữ o. Vậy với mã “1110110” giải đƣợc thông điệp “co”.

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

2.4. Xây dựng và cải tiến thuật toán

- Với cách thức thông thƣờng ta phải dùng thuật toán tìm kiếm theo chiều rộng BFS hoặc tìm kiếm theo chiều sâu DFS để tìm ra đƣờng đi từ gốc tới nút lá cần sinh mã. Sau đó sinh mã theo đƣờng đi đã tìm đƣợc (Độ phức tạp tính toán là O(n2), n là số đỉnh trong cây).

- Với mục đích sinh mã nhanh học viên đƣa ra giải pháp duyệt từ nút lá (nút cần sinh mã) về nút gốc. [1], [2]

- Xét ví dụ: Với chuỗi đầu vào là “thongtin”

Bƣớc 1: Lập bảng tần suất Kí tự Tần suất t 2 n 2 h 1 o 1 i 1 g 1 Tổng tần suất 8

Bƣớc 2: Xây dựng cây Huffman

Đỉnh Kí hiệu lá Trọng số

1 t 2

2 n 2

3 h 1

Số hóa bởi Trung tâm Học liệu - ĐHTN http://www.lrc.tnu.edu.vn/ 5 i 1 6 g 1 7 Ghép h với o 2 8 Ghép i với g 2 9 Ghép đỉnh 7 với n 4 10 Ghép đỉnh 8 với t 4 11 Ghép đỉnh 9 với đỉnh 10 8 - Biểu diễn các đỉnh nhƣ sau:

+ Đỉnh 1: + Đỉnh 2: + Đỉnh 3: + Đỉnh 4: + Đỉnh 5: 1 t 2 Số hiệu Kí hiệu lá Trọng số

Con trỏ trái Con trỏ phải

2 n 2 Số hiệu Kí hiệu lá Trọng số

Con trỏ trái Con trỏ phải (adsbygoogle = window.adsbygoogle || []).push({});

3 h 1 Số hiệu Kí hiệu lá Trọng số

Con trỏ trái Con trỏ phải

4 o 1 Số hiệu Kí hiệu lá Trọng số

Con trỏ trái Con trỏ phải

5 i 1 Số hiệu Kí hiệu lá Trọng số

Con trỏ trái Con trỏ phải

t p

t p

t p

Số hóa bởi Trung tâm Học liệu - ĐHTN http://www.lrc.tnu.edu.vn/ + Đỉnh 6: + Đỉnh 7: + Đỉnh 8: + Đỉnh 9: + Đỉnh 10: 6 g 1 Số hiệu Kí hiệu lá Trọng số

Con trỏ trái Con trỏ phải

7 Ɛ

2

Số hiệu Kí hiệu không phải là lá

Trọng số

Con trỏ trái Con trỏ phải

8 Ɛ

2

Số hiệu Kí hiệu không phải là lá

Trọng số

Con trỏ trái Con trỏ phải

9 Ɛ

4

Số hiệu Kí hiệu không phải là lá

Trọng số

Con trỏ trái Con trỏ phải

10 Ɛ

4

Số hiệu Kí hiệu không phải là lá

Trọng số (adsbygoogle = window.adsbygoogle || []).push({});

Con trỏ trái Con trỏ phải

t p t p t p t p t p t p

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

+ Đỉnh 11:

- Khi đó ta có cây Huffman nhƣ sau:

- Nhƣ vậy khi tổ chức con trỏ ngƣợc phƣơng thức sinh mã nhanh (trỏ phải là 1, trỏ trái là 0).

- Từ mã của các kí tự đƣợc sinh ra khi tổ chức con trỏ ngƣợc là:

11 Ɛ

8

Số hiệu Kí hiệu không phải là lá

Trọng số

Con trỏ trái Con trỏ phải

4 o 1 3 h 1 6 g 1 5 i 1 7 Ɛ 2 8 Ɛ 2 2 n 2 1 t 2 9 Ɛ 4 10 Ɛ 4 11 Ɛ 8 h=15 t p t p t p t p t p t p t p t p t p t p t p t p 111 011 110 010 01 00

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

o -> 010; h->110; g-> 011; i-> 111; n-> 00; t->01

Khi đó để có từ mã của các kí tự đƣợc sinh ra từ cây Huffman ta phải viết ngƣợc lại từ mã của các kí tự đƣợc sinh ra khi tổ chức con trỏ ngƣợc.

Kí tự Từ mã Độ dài t 10 2 n 00 2 h 011 1 o 010 1 i 111 1 g 110 1

Nhƣ vậy với mỗi ký hiệu đƣợc lƣu trữ bình thƣờng là 8 bit, khi đó với chuỗi đầu vào là “thongtin” thì ta phải mất 8 x 8 = 64 bit, trong khi đó sử dụng phƣơng pháp nén Huffman

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

CHƢƠNG 3: XÂY DỰNG CHƢƠNG TRÌNH NÉN SỬ DỤNG PHƢƠNG PHÁP MÃ HÓA HUFFMAN

3.1. Cấu trúc chƣơng trình

Chƣơng trình gồm hai nhóm thuật toán:

+ Nhóm thứ nhất: Gồm hai thuật toán chủ yếu là mã hóa Huffman và giải mã Huffman.

+ Nhóm thứ hai: Gồm các thuật toán trợ giúp cho hai quá trình mã hóa và giải mã.

Dƣới đây sẽ trình bày các thuật toán cơ bản nhất dƣới dạng ngôn ngữ phỏng trình. Chƣơng trình chi tiết đƣợc đặt trong phần phụ lục.

3.2. Các thuật toán nhóm một

3.2.1. Thuật toán A1: Nén Huffman (adsbygoogle = window.adsbygoogle || []).push({});

Chức năng: Nén Huffman file f ghi kết quả vào file g

Input: file f (gồm một dãy byte)

Output: file nén g Method

1. Đọc file f vào mảng s gồm m kí tự.

2. Xây dựng bảng tần suất T gồm n kí tự khác nhau trích từ s. Với mỗi kí tự c, T[c] = số lần xuất hiện c trong s.

3. Dựng cây Hufman h với con trỏ ngƣợc. (xem thuật toán A2) 4. Sinh mã Huffman cho từng kí tự của bảng T. (xem thuật toán A3) 5. Mã hóa s ghi vào dãy bit b.

6. Ghi b vào file g. end A1.

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

* Thực hiện giải thuật thuật toán A1 bằng ngôn ngữ Dev-C++ }

// Nen file f -> g

int EncodeFile(const char *f, const char *g, US mts = 256){ maxts = mts; // tan suat max

cout << "\n nen theo ti suat " << maxts; if (!CheckInput(f)) {

cout << endl << "Error: " << f

<< " too large or do not exitst \n"; cin.get(); exit(0);

}

Tinhfre(f); // Doc du lieu vao mang s[] Encode(f); // Nen

Write(g, b, (bitcount+7)/8); return true;

}

3.2.2. Thuật toán A2: Dựng cây Huffman

Chức năng: Dựng cây Huffman h với con trỏ ngƣợc.

Input: Bảng tần suất T[1..n] gồm n kí tự khác nhau trích từ s. Với mỗi kí tự c, T[c] = số lần xuất hiện c trong s.

Output: Cây Hufman với con trỏ ngƣợc h.

Method

for k = 1 to n do

- Tìm 2 đỉnh i và j chƣa xử lí và có trọng số min. - Tạo đỉnh mới h = n+k với trọng số T[h] = T[i] + T[j]

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

- Đặt con trỏ ngƣợc leftptr[i] = h và rightptr[j] = h - Đánh dấu hai đỉnh i và j là đã xử lí

Endfor k Return h end A2 (adsbygoogle = window.adsbygoogle || []).push({});

* Thực hiện giải thuật thuật toán A2 bằng ngôn ngữ Dev-C++ }

// Dung cay Huffman tu fre[0..nfre-1] void Tree() { int k, i, j, v; fre[EOF_CHAR] = MAXFRE; h = nfre-1; for (k = 1; k < nfre; ++k) { v = Min2(i,j);

++h; // Them dinh moi h fre[h] = v;

// Tao dinh moi

ptr[i] = h; go[i] = 0; // dinh i tro toi cha h ptr[j] = h; go[j] = 1; // dinh j tro toi cha h }

}

3.2.3. Thuật toán A3: Huffman code

Chức năng: Sinh mã Hufman cho các kí tự của bảng T

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

Output: Với mỗi kí tự c trong s sinh mã code[c] với số bit len[c] Method

for i=1 to n do

c = sym[i]; // sym[i] là kí tự thứ i trong bảng T i=j; code[c] = 0; len[c] = 0;

if pointer[j] = left then add bit 0 to code[c]; ++len[c];

j = left[i]

else add bit 1 to code[c] ++len[c]; j = right[i]; endif if j = h then break endfor end A3

* Thực hiện giải thuật thuật toán A3 bằng ngôn ngữ Dev-C++ } void GetCode(){ int i, p, j; int c; memset(len,0,sizeof(len)); memset(hcode,0,sizeof(hcode)); for (i = 0; i < nfre; ++i){

// Tinh ma cho ki tu sym[i]

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

//out << "\n xet dinh: "; while (p < h) { //cout << " " << p; wait(); if (go[p] == 1) SetBit(hcode[c],j); p = ptr[p]; ++j; } len[c] = j; } }

3.2.4. Thuật toán A4: Giải mã Huffman

Chức năng: Giải mã từ file nén g ghi kết quả vào file f

Input: file nén g

Output: file gốc f Method

Đọc file nén g vào dãy bit b goc: = h

While còn bit trong b do Đọc bit m trong b Nếu m = 1 rẽ phải Else rẽ trái

Nếu gặp kí tự c then ghi c vào f Quay về gốc

Endwhile endA4

Số hóa bởi Trung tâm Học liệu - ĐHTN (adsbygoogle = window.adsbygoogle || []).push({});

http://www.lrc.tnu.edu.vn/

* Thực hiện giải thuật thuật toán A4 bằng ngôn ngữ Dev-C++ }

void Decode(const char * gn) { int c;

int k;

GetHeader(); // Doc 4 byte vao n n = 0; n = GetIntbb(32); cout << "\n Decode, n = " << n; Tree(); GetCode(); DTree();

cout << endl << " Decoding..." << endl; Node * p = t; UC b; FILE *g; g = fopen(gn,"wb"); k = 0; while(1) { b = GetBitbb(); p = (b != 0) ? p->R : p->L; if (p->C != EOF_CHAR){

putc(p->C,g); // cout << (char)(p->C); p = t; ++k;

if (k == n) break; }

Số hóa bởi Trung tâm Học liệu - ĐHTN http://www.lrc.tnu.edu.vn/ } fclose(g); DelTree(t); }

3.3. Giới thiệu chƣơng trình

- Chƣơng trình đƣợc viết bằng ngôn ngữ Dev-C++. Đây là môi trƣờng lập trình mã nguồn mở.

- Phần chính của chƣơng trình bao gồm các lời gọi dạng

+ EncodeFile(f1,f2), trong đó f1 tên file dữ liệu cần nén, f2 là tên file kết quả (file nén).

Sau đó ta có thể kiểm định lại tính đúng đắn của thuật toán qua hai bƣớc sau:

- Bƣớc 1: Gọi hàm DecodeFile(f2, f3), trong đó f2 là tên file nén thu đƣợc sau khi thực hiện lệnh.

EncodeFile(f1,f2); f3 là tên file đƣợc giải nén từ file f2.

- Bƣớc 2: Gọi hàm FileCmp(f1,f3) để so sánh f1 và f3. Hàm này cho ra giá trị True nếu hai file có kích thƣớc giống nhau và giống nhau tại từng byte. Trong trƣờng hợp ngƣợc lại hàm cho ra giá trị False.

Sau khi thực hiện hai hàm EncodeFile(f1,f2) và DecodeFile(f2, f3) chƣơng trình tính tỉ lệ nén theo công thức sau:

Tỉ lệ nén đƣợc tính nhƣ sau: 100% 1

2

f f

Trong đó: f1 là dung lƣợng (số byte) của file f1

2

f là dung lƣợng (số byte) của f2

Ngoài ra chƣơng trình thông báo thêm một số thông tin sau đây: - Tên file nguồn.

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

- Tên file nén.

- Tên file bung (file mới thu đƣợc sau khi giải nén). - Kết quả đối sánh hai file.

- Tỉ lệ nén. (adsbygoogle = window.adsbygoogle || []).push({});

Chƣơng trình đã thử nghiệm với các kiểu file khác nhau nhƣ: - File văn bản soạn thảo bằng Microsoft word.

- File văn bản soạn thảo Notepad. - File chƣơng trình.

- File đồ họa. - File nhạc.

Dƣới đây là lời gọi kiểm thử chƣơng trình kết quả nhƣ sau:

Ví dụ 1: Nén flie luanvan.doc

Với File dữ liệu vào là luanvan.doc (f1) có dung lƣợng 71680 byte. File nén là Test2.huf (f2) co dung lƣợng 32053 byte.

File giải nén Testnew.doc (f3) có dung lƣợng 71680 byte. Tỉ lệ nén 44%. void Test1() { char * f1 = strdup("abc.doc"); char * f2 = strdup("abc.huf"); char * f3 = strdup("abcnew.cpp"); main() { Test1();

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/ Ví dụ 2: Nén flie abc.exe

Với File dữ liệu vào là abc.exe (f1) có dung lƣợng 1316775 byte. File nén là abc.huf (f2) co dung lƣợng 1082014 byte.

File giải nén abcnew.exe (f3) có dung lƣợng 1316775 byte. Tỉ lệ nén 82%. void Test2() { char * f1 = strdup("abc.exe"); char * f2 = strdup("abc.huf"); char * f3 = strdup("abcnew.exe"); main() { Test2();

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

3.4. Kết quả kiểm thử chƣơng trình

Với nhiều kiểu file dữ liệu đầu vào

Stt Tên file (kiểu file) Dung lƣợng Tỉ lệ nén File ban đầu File nén

1 Tài liệu adobe presenter (.doc) 901120 byte 698452 byte 22% 2 Tài liệu về nén dữ liệu (.doc) 133120 byte 96995 byte 27% 3 Tài liệu adobe captivate (.txt) 10286 byte 6638 byte 64% 4 File abc.exe (.exe) 1316775 byte 1082014 byte 82% 5 File text.cpp (.cpp) 108543 byte 69029 byte 63%

So sánh:

Sau đây là số liệu thống kê khi học viên sử dụng chƣơng trình nén tự lập trình và 2 chƣơng trình nén WinRAR và 7-Zip dành cho file

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

Stt Sử dụng

Dung lƣợng

File ban đầu File nén

1 Mã nén Huffman 911872 byte 809479 byte (88%)

2 Winra 911872 byte 572745 byte (63%)

3 Winzip 911872 byte 562245 byte (62%)

4 Mã nén Huffman 58621 byte 39750 byte (67%)

5 Winra 58621 byte 18718 byte (32%)

Số hóa bởi Trung tâm Học liệu - ĐHTN (adsbygoogle = window.adsbygoogle || []).push({});

http://www.lrc.tnu.edu.vn/

KẾT LUẬN

Mã nén ra đời đã đƣa ra một phƣơng pháp giảm dung lƣợng để lƣu trữ dữ liệu mà vẫn đảm bảo lƣu trữ đƣợc đúng thông tin. Điều này có ý nghĩa rất to lớn trong việc giảm chi phí, thời gian truyền thông tin trên mạng, tránh việc tắc nghẽn thông tin, giảm chi phí cho việc lƣu trữ. Các phƣơng pháp nén vẫn tiếp tục đƣợc cải tiến để có hiệu quả nén tốt hơn.

Ngày nay cùng với tốc độ tăng nhanh của lƣợng thông tin trên toàn cầu thì các phƣơng pháp nén dữ liệu ngày càng đƣợc sử dụng rộng rãi, tình hình đó cũng đặt ra yêu cầu phải phát triển lý thuyết nén hơn nữa, từ đó xây dựng các chƣơng trình nén có hiệu quả cao hơn và phải đƣợc áp dụng với nhiều kiểu dữ liệu. Qua thời gian làm luận văn, đƣợc sự hƣớng dẫn tận tình của thầy PGSTS Nguyễn Xuân Huy, sự giúp đỡ nhiệt tình của các thầy cô và các bạn, học viên đã hoàn thành đƣợc luận văn “ Tiếp cận mã Huffman theo tần suất và ứng dụng”. Đánh giá những việc đã làm đƣợc học viên nhận thấy:

- Luận văn đã trình bày đƣợc những kiến thức cơ bản nhất về nén dữ liệu. - Đã tìm hiểu đƣợc một số mã nén cơ bản đặc biệt là mã nén Huffman. - Đã cài đặt và cải tiến thành công thuật toán.

Tuy nhiên do thời gian và trình độ còn hạn chế, luận văn của học viên vẫn còn một số tồn tại sau:

- Chƣa tìm hiểu đƣợc phƣơng pháp nén tổn hao để nén các dữ liệu âm thanh và hình ảnh.

- Chƣơng trình chỉ có hiệu quả cao khi nén file văn bản mà chƣa áp dụng tốt cho các dạng dữ liệu khác.

- Cần phải nghiên cứu việc kết hợp các phƣơng pháp nén, cách xử lý tiết kiệm dung lƣợng hơn nữa để đạt đƣợc hiệu quả nén cao hơn.

Số hóa bởi Trung tâm Học liệu - ĐHTN

http://www.lrc.tnu.edu.vn/

- Học viên rất mong nhận đƣợc sự nhận xét, chỉ dẫn của các thầy cô, đóng

Một phần của tài liệu Tiếp cận mã huffman theo tần suất và ứng dụng (Trang 37 - 75)