Chương 3: PHƯƠNG PHÁP NÉN DỮ LIỆU
3.3 MÔ HÌNH TỪ ĐIỂN
3.3.2 Kỹ thuật từ điển
3.3.2.2 Các thuật toán nén LZ
LZ77 đƣợc phát minh ra năm 1977. Nó sử dụng từ điển là một đoạn văn bản gần với hiện tại.
Quá trình nén
Gọi vị trí kí tự đang đọc là hiện tại.
Gọi khoảng văn bản bắt đầu từ vị trí của kí tự đang đƣợc đọc đến hết văn bản là tương lai.
Gọi khoảng văn bản từ bắt đầu văn bản đến ngay trước vị trí kí tự đang được đọc là quá khứ.
Chúng ta chỉ tìm trong một khoảng N kí tự của quá khứ mà gần hiện tại nhất và tìm trong khoảng F kí tự đầu tiên trong tương lai và gọi F kí tự này là buffer.
Nguyên tắc nén như sau:
Bước 1: F – 1 kí tự đầu tiên giữ nguyên.
Bước 2: Cho buffer gồm F kí tự trong tương lai dịch dần về quá khứ N lần.
Mỗi lần đếm số kí tự trùng nhau liên tiếp kể từ đầu của buffer với quá khứ và ghi nhớ con số ấy tương ứng với các vị trí quá khứ mà buffer dịch đến. Tìm số lớn nhất trong tất cả các con số ấy.
Bước 3: Ghi ra mã gồm [i, j, w] trong đó i là khoảng cách từ vị trí hiện tại đến vị trí tương ứng với số lớn nhất vừa tìm được, j là số các kí tự trùng nhau hay chính là số lớn nhất vừa tìm đƣợc, w là kí tự ở vị trí thứ j + 1 trong buffer.
Bước 4: Lặp lại bước 2 cho đến khi hết văn bản.
Quá trình giả i nén
Bước 1: Đọc F – 1 kí tự đầu tiên của bản mã ghi ra bản giải mã.
Bước 2: Đọc một bộ mã [i, j, w]. Lùi về đoạn văn bản đã giải mã i vị trí và copy j kí tự từ vị trí thứ i đó để ghi ra bản giải mã, sau đó ghi ra w.
Bước 3: Nếu còn bộ mã thì quay lại bước 2. Nếu không còn thì kết thúc.
Ví dụ:
Cho văn bản sau bcabbcbccbababc. N = 11, F = 4.
Quá trình nén nhƣ sau:
TT Quá khứ Vị trí hiện tại Buffer Ghi ra
1 bca
2 bca 4 bbcb [3,1,b]
3 bcabb 6 cbcc [4,1,b]
4 bcabbcb 8 ccba [2,1,c]
5 bcabbcbcc 10 baba [3,1,a]
6 bcabbcbccba 12 babc [2,2,b]
7 bcabbcbccbaba 15 c [5,1,””]
Bảng 3.4: Quá trình nén xâu “bcabbcbccbababc” theo thuật toán LZ77 Bản mã là bca[3,1,b][4,1,b][2,1,c][3,1a][2,2,b][5,1,””]
Quá trình giải nén
TT Bộ mã đọc vào Ghi ra Bản giải mã
1 bca bca
2 [3,1,b] bb bcabb
3 [4,1,b] cb bcabbcb
4 [2,1,c] cc bcabbcbcc
5 [3,1,a] ba bcabbcbccba
6 [2,2,b] bab bcabbcbccbabab
7 [5,1,””] c bcabbcbccbababc
Bảng 3.5: Quá trình giải nén theo thuật toán LZ77bản mã bca[3,1,b][4,1,b][2,1,c][3,1a][2,2,b][5,1,””]
2/. Thuật toán LZ78
Đây là một trong các thuật toán từ điển động khá mạnh đƣợc phát minh và sử dụng trong những năm 1978. Từ điển xây dựng trong mã hoá và giải mã đơn giản và hoàn toàn động, do đó không cần lưu từ điển cùng file nén.
Quá trình nén
Thuật toán nén.
Bước 1: Khởi tạo từ điển có một phần tử là xâu rỗng có chỉ số 0. Xâu trung gian P rỗng.
Bước 2: Đọc kí tự tiếp theo trong văn bản vào C.
Bước 3: Tìm khúc (P + C) đã có trong từ điển chƣa?
Nếu có thì P ← P + C và quay lại bước 2.
Nếu không thì:
i. Cập nhật P + C vào trong từ điển.
ii. W ← chỉ số của P trong từ điển.
iii. Ghi cặp (W, C) ra bản mã.
iv. P ← rỗng.
Bước 4: Còn kí tự trong văn bản vào?
Nếu còn thì quay lại bước 2.
Nếu không còn thì ghi ra cặp (W, C) với C là rỗng.
Sơ đồ nén
Hình 3.11: Sơ đồ nén LZ78 Bắt đầu
Khởi tạo từ điển. Xâu trung gian P rỗng
Đọc kí tự tiếp theo vào C
P + C đã có
trong từ điển? P ← P + C
W ← chỉ số của P trong từ điển
Ghi ra bản mã (W, C) Cập nhật P + C vào từ điển
P ← rỗng
Còn kí tự trong văn bản?
C ← rỗng
Kết thúc Ghi ra bản mã (W, C) Đúng
Đúng
Sai
Sai
Quá trình giả i nén
Với mỗi cặp (W, C) ta ký hiệu .W nội dung của đoạn copy thứ W trong từ điển. Nếu W = 0 thì .W là rỗng.
Thuật toán giải nén.
Bước 1: Khởi tạo từ điển có một phần tử là xâu rỗng có chỉ số 0.
Bước 2: Đọc một cặp (W, C).
Bước 3: Ghi xâu (.W + C) ra bản giải mã. Cập nhật xâu này vào từ điển.
Bước 4: Còn kí tự trong bản mã không?
Nếu còn thì đọc cặp (W, C) tiếp theo và quay lại bước 2.
Nếu không thì kết thúc.
Sơ đồ giải nén
Hình 3.12: Sơ đồ giải nén thuật toán LZ78 Bắt đầu
Khởi tạo từ điển
Đọc một cặp (W, C)
Ghi (.W + C) ra bản giải mã
Cập nhật (.W + C) vào từ điển
Còn kí tự trong bản mã?
Kết thúc Đúng
Sai
Ví dụ:
Cho văn bản aaabbabaabaaabab.
Quá trình nén
TT Đoạn văn bản đã
mã P C Từ điển W Ghi
ra
1 a “” a 0 – “”, 1 – a 0 (0,a)
2 aaa a a 0 – “”, 1- a, 2 - aa 1 (1,a)
3 aaab “” b 0 – “”, 1- a, 2 – aa, 3- b 0 (0,b) 4 aaabba b a 0 – “”, 1- a, 2 – aa, 3 – b, 4 - ba 3 (3,a) 5 aaabbabaa ba a 0 – “”, 1- a, 2 – aa, 3 – b, 4 – ba,
5 – baa 4 (4,a)
6 aaabbabaabaaa baa a 0 – “”, 1- a, 2 – aa, 3 – b, 4 – ba,
5 – baa, 6 - baaa 5 (5,a) 7 aaabbabaabaaabab ba b 0 – “”, 1- a, 2 – aa, 3 – b, 4 – ba,
5 – baa, 6 – baaa, 7 - bab 4 (4,b) Bảng 3.6: Quá trình nén xâu “ aaabbabaabaaabab” bằng thuật toán LZ78 Kết quả bản mã gồm các cặp sau: (0,a)(1,a)(0,b)(3,a)(4,a)(5,a)(4,b)
Quá trình giải nén
TT Cặp mã đọc vào
Ghi
ra Từ điển Xâu kết quả
1 (0,a) a 0 – “”, 1 - a a
2 (1,a) aa 0 – “”, 1 – a, 2 – aa aaa
3 (0,b) b 0 – “”, 1 – a, 2 – aa, 3 – b aaab 4 (3,a) ba 0 – “”, 1 – a, 2 – aa, 3 – b, 4 - ba aaabba 5 (4,a) baa 0 – “”, 1 – a, 2 – aa, 3 – b, 4 – ba, 5 –
baa aaabbabaa
6 (5,a) baaa 0 – “”, 1 – a, 2 – aa, 3 – b, 4 – ba, 5 –
baa, 6 – baaa aaabbabaabaaa
7 (4,b) bab 0 – “”, 1 – a, 2 – aa, 3 – b, 4 – ba, 5 –
baa, 6 – baaa, 7 - bab aaabbabaabaaabab Bảng 3.7: Quá trình nén bằng thuật toán LZ78 bản mã
“(0,a)(1,a)(0,b)(3,a)(4,a)(5,a)(4,b)”
Kết quả giải mã ta đƣợc: aaabbabaabaaabab
Thuật toán này có ưu điểm là mã hoá và giải mã tương đối nhanh tuy nhiên vẫn còn hạn chế trong hiệu quả nén (đối với file văn bản đạt trung bình 40%, chỉ đạt hiệu quả cao khi nén các file lớn).
3/. Thuật toán LZW
LZW được đặt tên từ những người tạo ra nó A.Lempel, J.Ziv và Terry A.Welch. Đây là phương pháp nén file mới nhất, hiệu quả nén trung bình là 50%. Nó không chỉ đƣợc sử dụng cho file .doc, .txt mà còn cho cả file hình ảnh nhƣ file .gif…
Điểm khác biệt giữa LZ78 và LZW trong nguyên lý nén.
Khởi tạo từ điển bao gồm tất cả các kí tự trong bảng chữ cái ban đầu.
Kí tự cuối cùng của đoạn copy này là kí tự đầu của đoạn copy sau.
Bản mã chỉ là chỉ số các đoạn copy chứ không có các kí tự nữa.
Quá trình nén Thuật toán nén
Bước 1: Khởi tạo từ điển gồm các kí tự trong bảng chữ cái của văn bản xuất hiện trong văn bản đƣợc đánh chỉ số từ 0. Xâu trung gian P rỗng.
Bước 2: Đọc kí tự tiếp theo trong văn bản vào C.
Bước 3: Xâu P + C đã có trong từ điển chƣa?
Nếu có thì P ← P + C Nếu không thì:
i. Ghi ra bản mã chỉ số của P trong từ điển.
ii. Thêm xâu P + C vào từ điển.
iii. P ← C (lúc này P chứa một kí tự).
Bước 4: Còn kí tự nào trong văn bản không?
Nếu có thì quay lại bước 2.
Nếu không thì:
i. Ghi ra bản mã chỉ số của P trong từ điển.
ii. Kết thúc.
Sơ đồ nén
Hình 3.13: Sơ đồ nén dữ liệu thuật toán LZW Bắt đầu
Khởi tạo từ điển. Xâu trung gian P rỗng
Đọc kí tự tiếp theo vào C
P + C đã có
trong từ điển? P ← P + C
W ← chỉ số của P trong từ điển
Ghi ra bản mã W
Cập nhật P + C vào từ điển
P ← C
Còn kí tự trong văn bản?
W ← chỉ số của P trong từ điển
Kết thúc Ghi ra bản mã W Đúng
Đúng
Sai
Sai
Quá trình giải nén
Gọi cW là từ mã đang đƣợc giải mã. Ký hiệu .cW là nội dung đoạn copy có ký hiệu cW trong từ điển.
Gọi pW là từ mã đứng trước từ mã hiện thời trong bản mã. Ký hiệu .pW là nội dung đoạn copy có ký hiệu pW trong từ điển.
Nguyên lý của giải mã nhƣ sau:
Tại thời điểm khởi tạo thì từ điển giống nhƣ lúc mã hoá.
Tại thời điểm bất kỳ trong quá khứ, khi từ điển chứa vài đoạn copy dài hơn.
Ghi nhớ từ mã trước pW.
Đọc từ mã hiện thời cW từ bản mã.
Đƣa ra đoạn copy .cW.
Cộng đoạn copy .pW với kí tự đầu tiên của đoạn copy .cW và thêm vào từ điển.
Hai từ mã pW và cW liên tiếp nhau trong bản mã, khi đó kí tự cuối cùng của .pW là kí tự đầu tiên của .cW.
Chú ý: trong quá trình nén thuật toán thêm một đoạn copy vào từ điển trước khi toàn bộ đoạn đó đƣợc nén, đó là kí tự cuối của đoạn copy (đƣợc xử lý ở trong đoạn copy sau). Nếu vì một lý do nào đó mà trình nén sử dụng ngay lập tức đoạn copy này thì khi giải nén sẽ có vấn đề là gặp phải mã của một đoạn copy mà nó lại chƣa xuất hiện trong từ điển (còn thiếu một kí tự cuối cùng là kí tự đầu tiên của đoạn copy đƣợc giải mã tiếp theo).
Ví dụ:
Giả sử đoạn copy IWOMBAT đã có trong từ điển với chỉ số là 300 (tức là mã của đoạn copy này là 300), còn đoạn copy IWOMBATI thì chƣa có trong từ điển.
Khi gặp đoạn văn bản IWOMBATIWOMBATI trình nén sẽ đƣa ra mã là 300 và thêm vào từ điển đoạn copy IWOMBATI, giả sử với mã là 400. Và sử dụng ngay mã 400 cho đoạn copy tiếp theo. Khi đó cả đoạn văn bản trên có mã là <300><400>.
Xét quá trình giải nén: sau khi thay <300> bằng đoạn copy IWOMBAT thì trình giải nén gặp mã <400>. Nhƣng khi đó trong từ điển của trình giải nén chƣa có
Cho nên trong nguyên lý giải nén việc đƣa ra đoạn copy .cW không phải lúc nào cũng thực hiện được. Tuy nhiên, nó cũng chỉ không thành công trong trường hợp gặp đoạn văn bản có dạng nhƣ trong ví dụ này. Vì để đƣa ra đoạn copy của cW trong từ điển chúng ta cũng chỉ thiếu có một kí tự cuối và kí tự này xuất hiện ở đầu của đoạn copy .cW. Do đó, trong trường hợp này thì đoạn .pW được mở rộng bằng thêm kí tự đầu tiên của nó, xâu kết quả đƣợc ra và thêm nó vào từ điển.
Thuật toán giải nén
Bước 1: Khởi tạo từ điển ban đầu gồm các kí tự trong bảng chữ cái của văn bản xuất hiện trong văn bản, đƣợc đánh chỉ số từ 0.
Bước 2: cW ← từ mã đầu tiên trong bản mã.
Bước 3: Ghi đoạn copy .cW ra bản giải mã.
Bước 4: pW ← cW.
Bước 5: cW ← từ mã tiếp theo trong bản mã.
Bước 6: Đoạn copy .cW có trong từ điển không?
Nếu có thì
i. Ghi đoạn copy .cW ra bản giải mã.
ii. p ← .pW
iii. c ← kí tự đầu tiên của đoạn copy .cW iv. Thêm đoạn copy p + c vào từ điển.
Nếu không thì i. p ← .pW
ii. c ← kí tự đầu tiên của đoạn copy .pW
iii. Ghi đoạn copy p + c ra bản giải mã và thêm nó vào từ điển.
Bước 7: Còn từ mã nào trong bản mã không?
Nếu có thì quay về bước 4.
Nếu không thì kết thúc
Sơ đồ giải nén
cW ← từ mã đầu tiên
Ghi .cW ra bản giải mã
cW ← từ mã tiếp theo
Ghi .cW ra bản giải mã p ← .pW
c ← kí tự đầu tiên của .pW
Ghi p + c ra bản giải mã
Cập nhật p + c vào từ điển Bắt đầu
Khởi tạo từ điển.
Đúng
Đúng pW ← cW
.cW đã có trong từ điển?
c ← kí tự đầu tiên của .cW
Cập nhật p + c vào từ điển
Sai
p ← .pW
Còn kí tự trong văn bản?
Sai
Ví dụ:
Cho văn bản aabababaaababb Quá trình nén
TT Xâu đã xét P C Từ điển Ghi
ra
1 aa a a 0 – a, 1 – b, 2 - aa 0
2 aab a b 0 – a, 1 – b, 2 – aa, 3 - ab 0
3 aaba b a 0 – a, 1 – b, 2 – aa, 3 – ab, 4 - ba 1 4 aababa ab a 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 -
aba 3
5 aabababaa aba a 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 –
aba, 6 – abaa 5
6 aabababaaab aa b 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 –
aba, 6 – abaa, 7 – aab 2
7 aabababaaabab ba b 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 – aba, 6 – abaa, 7 – aab, 8 – bab 4 8 aabababaaababb b b 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 –
aba, 6 – abaa, 7 – aab, 8 – bab, 9 – bb 1 9 aabababaaababb 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 –
aba, 6 – abaa, 7 – aab, 8 – bab, 9 – bb 1 Bảng 3.8: Quá trình nén xâu “aabababaaababb” bằng thuật toán LZW
Vậy bản mã là 001352411
Quá trình giải nén
TT pW cW Từ điển Ghi ra
0 0 0 – a, 1 – b a
1 0 0 0 – a, 1 – b, 2 – aa a
2 0 1 0 – a, 1 – b, 2 – aa, 3 - ab b
3 1 3 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba ab 4 3 5 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 – aba aba 5 5 2 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 – aba, 6 – abaa aa 6 2 4 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 – aba, 6 –
abaa, 7 – aab ba
7 4 1 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 – aba, 6 –
abaa, 7 – aab, 8 – bab b
8 1 1 0 – a, 1 – b, 2 – aa, 3 – ab, 4 – ba, 5 – aba, 6 –
abaa, 7 – aab, 8 – bab, 9 - bb b
Bảng 3.9: Quá trình giải nén bản mã “001352411” theo thuật toán LZW Kết quả thu đươc là aabababaaababb.
Nhận xét
Phương pháp này rất thông dụng trong thực tiễn, thuận lợi hơn so với LZ78 do hiệu quả nén cao hơn (trung bình khoảng 70% đối với file văn bản). Cải tiến hơn về kích thước từ mã (phụ thuộc vào kích thước từ điển).