Tải bản đầy đủ (.pdf) (96 trang)

MÃ HOÁ NÉN DỮ LIỆU VÀ MÃ HOÁ CÓ KHẢ NĂNG PHÁT HIỆN SAI VÀ SỬA SAI

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1008.35 KB, 96 trang )

ðẠI HỌC THÁI NGUYÊN
TRƯỜNG ðẠI HỌC SƯ PHẠM
KHOA TOÁN









MÃ HOÁ NÉN DỮ LIỆU VÀ
MÃ HOÁ CÓ KHẢ NĂNG PHÁT HIỆN
SAI VÀ SỬA SAI




LUẬN VĂN TỐT NGHIỆP ðẠI HỌC






THÁI NGUYÊN
ðẠI HỌC THÁI NGUYÊN
TRƯỜNG ðẠI HỌC SƯ PHẠM
KHOA TOÁN








LÊ QUÝ TÀI


MÃ HOÁ NÉN DỮ LIỆU VÀ
MÃ HOÁ CÓ KHẢ NĂNG PHÁT HIỆN
SAI VÀ SỬA SAI


Chuyên ngành: Tin học

LUẬN VĂN TỐT NGHIỆP ðẠI HỌC

Người hướng dẫn khoa học: Thạc sỹ Nguyễn Văn Trường





THÁI NGUYÊN – 2007

2

LỜI NÓI ðẦU
Máy tính ra ñời giúp con người lưu trữ và xử lý thông tin, bên cạnh việc
xử lý nhanh, người ta còn quan tâm ñến việc lưu trữ ñược nhiều thông tin

nhưng lại tiết kiệm ñược bộ nhớ và giảm chi phí lưu trữ. Mặt khác, khi mạng
máy tính ra ñời, nhu cầu trao ñổi thông tin lại càng lớn hơn, dẫn ñến nhu cầu
phải giảm thiểu thời gian và chi phí ñể trao ñổi dữ liệu trên mạng. Khi truyền
tin, có thể vì một lí do nào ñó mà tập tin bị lỗi, một câu hỏi ñặt ra là có thể
khôi phục lại tập tin ban ñầu từ tập tin lỗi ñó hay không?
Tất cả những vấn ñề trên nảy sinh ra khái niệm nén dữ liệu, nén dữ liệu
nhằm tiết kiệm không gian lưu trữ cũng như tăng hiệu suất truyền tin, ñồng
thời ñây cũng là một phương pháp ñể bảo mật dữ liệu. Cùng với nén dữ liệu
thì mã hoá có khả năng phát hiện sai và sửa sai cũng phát triển mạnh bởi
ñây là phương pháp mã hoá giúp tăng ñộ tin cậy của dữ liệu khi truyền ñi
trên mạng.
ðể giải quyết những yêu cầu ñó, cách ñây khoảng nửa thế kỉ, nhiều nhà
khoa học ñã phát minh ra những thuật toán ñể phục vụ cho việc nén dữ liệu
cũng như phát hiện và sửa sai. ðến nay, những thuật toán ñó ñã ñược cải tiến,
tối ưu, ñồng thời nhiều thuật toán mới cũng ra ñời. Vì vậy, tôi ñã chọn nghiên
cứu ñề tài: “Mã hoá nén dữ liệu và mã hoá có khả năng phát hiện sai và
sửa sai” với mục ñích tìm hiểu các thuật toán ñó và cài ñặt một số thuật toán
bằng ngôn ngữ lập trình cụ thể nhằm làm sáng rõ và cải tiến thuật toán.
Trong thời gian làm ñề tài, tôi ñã nhận ñược sự giúp ñỡ, chỉ dẫn của
Thạc sỹ Nguyễn Văn Trường. ðồng thời tôi cũng nhận ñược những ý kiến
ñóng góp của các bạn ñồng nghiệp. Vì thời gian làm ñề tài có hạn nên chắc
chắn không tránh khỏi những thiếu sót, rất mong nhận ñược những góp ý của
các quý thầy cô và các bạn ñể ñề tài chất lượng và thiết thực hơn.
Tôi xin chân thành cảm ơn!
Sinh viên
Lê Quý Tài


3


MỤC LỤC
LỜI NÓI ðẦU 2

MỤC LỤC 3

MỞ ðẦU 5

1. Lí do chọn ñề tài 5

2. Lịch sử nghiên cứu ñề tài 5

3. Mục ñích nghiên cứu ñề tài 6

4. Giới hạn của ñề tài 6

5. Phương pháp nghiên cứu 7

6. Cấu trúc của ñề tài 7

Chương 1. NHỮNG KIẾN THỨC LIÊN QUAN 8

1.1. Cấu trúc dữ liệu cây 8

1.1.1. ðịnh nghĩa và các khái niệm 8

1.1.2. Cây nhị phân 9

1.2. Cấu trúc dữ liệu kiểu con trỏ 12

1.2.1. Khái niệm 12


1.2.2. Sử dụng con trỏ xây dựng cây nhị phân 15

1.3. Vài nét về ngôn ngữ lập trình C và C
++
17

1.4. Vài nét về ngôn ngữ lập trình Visual Basic 19

Chương 2. CÁC KHÁI NIỆM CƠ BẢN 21

2.1. ðịnh nghĩa và các khái niệm về mã hoá 21

2.1.1. ðịnh nghĩa 21

2.1.2. Một số khái niệm cơ bản về mã hoá 22

2.1.3. Các phương pháp biểu diễn mã 23

2.1.4. ðiều kiện ñể mã phân tách ñược và mã có tính Prefix 26

2.2. Mã hoá nén dữ liệu 27

2.2.1. Khái niệm 27



4

2.2.2. Tầm quan trọng của việc nén dữ liệu 28


2.2.3. Phân loại 29

2.2.4. Giới thiệu một số chuẩn nén 30

2.3. Mã hoá có khả năng phát hiện sai và sửa sai 31

2.3.1. Khái niệm 31

2.3.2. Tầm quan trọng của việc mã hoá sửa sai 31

Chương 3. THUẬT TOÁN NÉN DỮ LIỆU 32

3.1. Các thuật toán nén dữ liệu theo kiểu thống kê 32

3.1.1. Phương pháp mã hoá ñộ dài loạt 32

3.1.2. Mã Shanon - Fano 34

3.1.3. Mã Huffman 39

3.1.4. Mã số học 50

3.2. Các thuật toán nén dữ liệu theo kiểu từ ñiển 54

3.2.2. Thuật toán LZ77 - LZ78 55

3.2.3. Thuật toán LZW 61

Chương 4. MÃ PHÁT HIỆN SAI VÀ SỬA SAI 74


4.1. Mã Hamming 74

4.2. Mã CRC 82

KẾT LUẬN 89

TÀI LIỆU THAM KHẢO 91

PHỤ LỤC 93



5

MỞ ðẦU
1. Lí do chọn ñề tài
Trong nhiều năm gần ñây, kết nối mạng máy tính ñã trở nên phổ biến
trên thế giới. Sự ra ñời của mạng máy tính ñã thực hiện ñược ước mơ chinh
phục khoảng cách giữa con người. Những lợi ích mà mạng cung cấp rất ña
dạng và phong phú như: cung cấp, trao ñổi thông tin giữa các máy tính, giữa
máy tính với máy chủ hoặc giữa các máy chủ với nhau. ðiều này ñòi hỏi phải
có phương pháp nén dữ liệu ñể nâng cao chất lượng, tốc ñộ truyền tin và giảm
thiểu chi phí.
Trong quá trình truyền tải dữ liệu, có thể vì một lí do nào ñó mà tập dữ
liệu bị hỏng, ñòi hỏi cần có phương pháp giúp khôi phục lại tập tin ban ñầu từ
tập tin bị hỏng.
Nhiều thuật toán nén dữ liệu ñã ñược phát minh, phát triển và tối ưu qua
nhiều năm và ñược ứng dụng trong nhiều sản phẩm phần mềm có giá trị phục
vụ cho người dùng máy tính. Việc tìm hiểu, cài ñặt và tối ưu các thuật toán ñó

là một yêu cầu cấp thiết ñang ñặt ra. Vì vậy, tôi ñã mạnh dạn chọn nghiên cứu
ñề tài “Mã hoá nén dữ liệu và mã hoá có khả năng phát hiện sai và sửa
sai”. Trên cơ sở ñề tài này, tôi sẽ nghiên cứu và phát triển phần mềm nén dữ
liệu với khả năng nén cao và hiệu quả.
2. Lịch sử nghiên cứu ñề tài
Những nền tảng ban ñầu của lĩnh vực nén dữ liệu ñã xuất hiện vào những
năm 1940 cùng với sự phát triển của lí thuyết thông tin. Những khái niệm ban
ñầu ñã ñược ñưa ra cuối những năm 1940 bởi Claude Shanon tại phòng thí
nghiệm Bell. Nén dữ liệu liên quan ñến hàng loạt vấn ñề thông tin, bao gồm
việc lưu trữ và truyền thông tin.
Các nhà nghiên cứu ñã ñưa ra các phương pháp khác nhau ñể nén dữ
liệu, trong ñó hai thuật toán mã Huffman và mã Shanon - Fano ñược công bố
khá sớm. Thuật toán mã Huffman ñược David A. Huffman ñưa ra năm 1952
và ñược chấp nhận rộng rãi và luôn ñược sử dụng cho các chương trình nén


6

dữ liệu trước năm 1980, còn thuật toán mã Shanon - Fano do Claude Shanon
công bố. Do tính ñơn giản, dễ xây dựng, không quá tốn thời gian của CPU
nên vẫn ñược sử dụng rộng rãi.
ðến năm 1980, hầu hết các phương pháp nén ñều sử dụng phương pháp
thống kê. Nhưng vào năm 1977 - 1978, Jacov Ziv và Abraham Lempel ñã mô
tả một cặp phương pháp nén sử dụng kết hợp từ ñiển, ñã ñạt ñược một tỉ lệ
nén ñầy ấn tượng. ðến năm 1984, Terry Welch’s ñã phát triển thuật toán
LZ78 và ñưa ra giới thiệu thuật toán nén dữ liệu LZW (Lempel-Ziv-Welch).
Mã Hamming ñược R. W. Hamming ñưa ra và ñược dùng trong một số
hệ thống sử dụng kĩ thuật Forward Error Correction (FEC), mã này có khả
năng sửa sai một lỗi, mã Hamming ñược sử dụng khá rộng rãi trong thực tế.
Ngoài ra, còn rất nhiều phương pháp khác ñể nén dữ liệu cũng như ñể

kiểm tra và sửa lỗi: phương pháp của Meggit, Kasamin, Mitchell và Rudolph,
giải thuật của Berlekamp…
3. Mục ñích nghiên cứu ñề tài
Với ñề tài “Mã hoá nén dữ liệu và mã hoá có khả năng phát hiện sai và
sửa sai”, chúng tôi có mục ñích nghiên cứu:
- Khái niệm tổng quan về mã hoá và mã hoá nén dữ liệu, mã hoá có khả
năng phát hiện sai và sửa sai.
- Tìm hiểu các thuật toán nén dữ liệu và cài ñặt bằng ngôn ngữ lập trình
một số thuật toán nén dữ liệu tiêu tiểu.
- Tìm hiểu về phương pháp mã hoá có khả năng phát hiện sai và sửa sai
và cài ñặt mô phỏng bằng ngôn ngữ lập trình.
Tuy nhiên, do khái niệm mã hoá nói chung cũng như mã hoá nén dữ liệu
và mã hoá có khả năng phát hiện sai và sửa sai khá rộng và phức tạp, do ñó,
với khuôn khổ của một luận văn tốt nghiệp, chúng tôi chỉ giới hạn nghiên cứu
những nội dung dưới ñây.
4. Giới hạn của ñề tài
- Nghiên cứu những nét tổng quan về mã hoá nói chung, mã hoá nén dữ
liệu và mã hoá có khả năng phát hiện sai và sửa sai.


7

- Tiến hành cài ñặt bằng ngôn ngữ lập trình một số thuật toán nén dữ liệu
và mã hoá sửa sai tiêu biểu, các thuật toán khác chỉ ñược trình bày những nét
khái quát và không có chương trình cài ñặt cụ thể.
5. Phương pháp nghiên cứu
Với những nội dung giới hạn trên ñây và dựa vào những yêu cầu của ñề
tài và tình hình thực tế, chúng tôi ñã chọn những phương pháp nghiên cứu
sau:
- Phương pháp nghiên cứu tài liệu.

- Phương pháp tổng hợp, khái quát hoá
- Phương pháp thực nghiệm
6. Cấu trúc của ñề tài
Căn cứ theo mục ñích nghiên cứu cũng như giới hạn của ñề tài, chúng tôi
chia ñề tài làm 4 chương, với các nội dung chủ yếu của mỗi chương như sau:
Chương 1. Những kiến thức liên quan: Trình bày những kiến thức có
liên quan có sử dụng khi viết chương trình như: cấu trúc dữ liệu ñộng, cấu
trúc dữ liệu kiểu con trỏ, cấu trúc dữ liệu cây…, và một vài nét về các ngôn
ngữ lập trình ñược sử dụng ñể viết chương trình (C++, Visual Basic).
Chương 2. Các khái niệm cơ bản: Trình bày các ñịnh nghĩa và khái
niệm cơ bản về mã hoá, mã hoá nén dữ liệu và mã hoá có khả năng phát hiện
sai và sửa sai.
Chương 3. Thuật toán nén dữ liệu: Trình bày các thuật toán nén dữ liệu
ñược phân loại theo phương pháp nén, ñồng thời trình bày chi tiết về chương
trình cài ñặt minh hoạ.
Chương 4. Mã phát hiện sai và sửa sai: Trình bày các phương pháp mã
hoá có khả năng phát hiện sai và sửa sai cùng với mô tả chi tiết việc cài ñặt
minh hoạ của thuật toán.



8

Chương 1. NHỮNG KIẾN THỨC LIÊN QUAN
Chương này trình bày những kiến thức liên quan có sử dụng khi cài ñặt
các thuật toán nén dữ liệu và mã hoá sửa sai. ðây là các kiến thức cơ sở giúp
xây dựng chương trình, vì vậy, chúng tôi sẽ chú ý ñến việc thể hiện của các
kiến thức này trên ngôn ngữ lập trình (cụ thể là ngôn ngữ lập trình C).
1.1. Cấu trúc dữ liệu cây
1.1.1. ðịnh nghĩa và các khái niệm

Một cây (tree) là một tập hợp hữu hạn các nút trong ñó có một nút dặc
biệt ñược gọi là gốc (root), giữa các nút có quan hệ phân cấp gọi là quan hệ
“cha-con”.
ðịnh nghĩa cây một cách ñệ quy:
1. Một nút là một cây, nút ñó cũng là gốc của cây ấy.
2. Nếu T
1
, T
2
, …, T
k
là các cây, với n
1
, n
2
, …, n
k
lần lượt là các gốc. n là
một nút và n có quan hệ cha con với n
1
, n
2
, …, n
k
thì lúc ñó một cây mới T sẽ
ñược tạo lập, với n là gốc của nó, n ñược gọi là cha của n
1
, n
2
, …, n

k
; ngược
lại n
1
, n
2
, …, n
k
ñược gọi là con của n. Các cây T
1
, T
2
, …, T
k
ñược gọi là các
cây con (subtrees) của n. [6]
Quy ước: một cây không có nút nào ñược gọi là cây rỗng (null tree).
Chẳng hạn, hình 1.1 dưới ñây biểu diễn một cây:






Hình 1.1. Một cây
A

B

C


D

E

F

G

H

I



9

Số các con của một nút gọi là cấp (degree) của nút ñó. Ví dụ, cấp của A
là 3, cấp của H là 2.
Nút có cấp bằng không gọi là lá (leaf) hay nút tận cùng (terminal node),
ví dụ các nút E, C, K,… nút không có lá ñược gọi là nút nhánh (branch node).
Cấp cao nhất của nút trên cây gọi là cấp của cây ñó. Ví dụ, cây hình 1.1
là cây cấp 3.
Gốc của cây có số mức (level) là 1. Nếu nút cha có số mức là i thì nút
con có số mức là i+1. Ví dụ A có mức 1, D có mức 2.
Chiều cao (heigh) hay chiều sâu (depth) của một cây là số mức lớn nhất
của nút ñó có trên cây ñó. Ví dụ, cây hình 1.1 có chiều cao 4.
Nếu n
1
, n

2
, …, n
k
là dãy nút mà n
i
là cha của n
i+1
với 1 ≤ i < k, thì dãy ñó
gọi là ñường ñi (path) từ n
1
tới n
k
. Ví dụ, trong hình 1.1 ñộ dài ñường ñi từ A
ñến K là 3.
Nếu thứ tự các cây con của một nút ñược coi trọng thì cây ñang xét là
cây thứ tự (ordered tree), ngược lại là cây không có thứ tự (unordered tree).
Thường thứ tự các cây con của một nút ñược ñặt từ trái sang phải.
Nếu một tập hữu hạn các cây phận biệt thì ta gọi ñó là rừng (forest).
1.1.2. Cây nhị phân
1.1.2.1. ðịnh nghĩa
Cây nhị phân là một cây mà mỗi nút trên cây chỉ có tối ña hai con.
ðối với cây nhị phân người ta cũng phân biệt cây con trái (left subtree)
và cây con phải (right subtree). Như vậy, cây nhị phân là cây có thứ tự.
Cây nhị phân hoàn chỉnh (complete binary tree) là cây nhị phân mà các
nút ứng với các mức trừ mức cuối cùng ñều ñạt tối ña và ở mức cuối các nút
ñều dạt về phía trái. Cây nhị phân ñầy ñủ (full binary tree) là cây nhị phân mà
các nút tối ña ở mọi mức. Cây gần ñầy là cây nhị phân mà các nút ứng với các
mức trừ mức cuối cùng ñều ñạt tối ña.[6]




10

1.1.2.2. Biểu diễn cây nhị phân
a) Lưu trữ kế tiếp
Ta ñánh số cho các nút trên cây theo thứ tự lần lượt từ mức 1 trở lên, hết
mức này ñến mức khác. Ta nhận thấy:
Con của nút thứ i là các nút thứ 2i và 2i+1 hoặc cha của nút thứ j là [j/2].
Như vậy, ta lưu trữ cây nhị phân ñầy ñủ bằng một vector V theo nguyên tắc:
nút thứ i của cây ñược lưu trữ ở V[i]. Tuy nhiên, với cây nhị phân dạng khác
thì cách lưu trữ này gây lãng phí nhiều ô nhớ.
b) Lưu trữ móc nối
Trong cách lưu trữ này, mỗi nút ứng với một phần tử nhớ có quy cách
như sau:
LPTR INFO RPTR
- Trường INFO ứng với thông tin (dữ liệu) của nút.
- Trường LPTR ứng với con trỏ, trỏ tới cây con trái của nút ñó.
- Trường RPTR ứng với con trỏ, trỏ tới cây con phải của nút ñó.
ðể có thể truy cập vào các nút cây cần có một con trỏ T, trỏ tới nút gốc
của cây ñó.
Ví dụ: Hình 1.2 mô tả một cây nhị phân và hình 1.3 là biểu diễn cây nhị
phân ñó dưới dạng lưu trữ móc nối:












Hình 1.2. Một cây nhị phân
B

A

C

D

E

F

G

H

I



11












Hình 1.3. Một cây nhị phân ñược dưới dạng lưu trữ móc nối
Quy ước: Nếu cây nhị phân rỗng thì T=null.
Với cách biểu diễn này từ nút cha có thể truy cập trực tiếp vào nút con,
nhưng ngược lại thì không làm ñược.
1.1.2.3. Duyệt cây nhị phân
Phép xử lý các nút trên cây - phép toán thăm (visit) các nút - một cách hệ
thống, sao cho mỗi nút chỉ ñược thăm một lần, gọi là phép duyệt cây
Các phép duyệt cây ñược ñịnh nghĩa một cách ñệ quy như sau:
a) Duyệt cây theo thứ tự trước (preorder traversal)
1) Nếu cây rỗng thì không làm gì.
2) Nếu cây không rỗng thì:
- Thăm gốc;
- Duyệt cây con trái theo thứ tự trước;
- Duyệt cây con phải theo thứ tự trước.
Ví dụ: thứ tự duyệt cây ở hình 1.2: A B D E C F G H I
b) Duyệt cây theo thứ tự giữa (inorder traversal)
1) Nếu cây rỗng thì không làm gì.
2) Nếu cây không rỗng thì:
- Duyệt cây con trái theo thứ tự giữa;
A

B

C


X D X

X E X

G

X F X

X H X

X I X

T


12
- Thăm gốc;
- Duyệt cây con phải theo thứ tự giữa.
Ví dụ: thứ tự duyệt cây ở hình 1.2: D B E A F C H G I
c) Duyệt theo thứ tự sau (postorder traversal)
1) Nếu cây rỗng thì không làm gì.
2) Nếu cây không rỗng thì:
- Duyệt cây con trái theo thứ tự sau;
- Duyệt cây con phải theo thứ tự sau;
- Thăm gốc.
Ví dụ: thứ tự duyệt cây ở hình 1.2: D E B F H I G C A
1.2. Cấu trúc dữ liệu kiểu con trỏ
Trong phần này, chúng tôi sẽ trình bày khái niệm, cách sử dụng và ứng
dụng của kiểu dữ liệu con trỏ trong ngôn ngữ lập trình C (ngôn ngữ lập trình

ñược dùng chính ñể cài ñặt các thuật toán).
1.2.1. Khái niệm
Khi khai báo một biến, chẳng hạn
int i=10;
hệ thống sẽ cấp phát một
vùng nhớ gồm 2 byte liên tiếp cho biến
i
. ðịa chỉ của biến là chỉ số của byte
ñầu tiên trong dãy các byte liên tiếp mà hệ thống dành cho biến. Như vậy, một
biến sẽ có 3 ñặc trưng: ñịa chỉ của biến, số byte lưu trữ, giá trị hiện thời. Từ
ñịa chỉ của biến, chúng ta có thể duyệt ñược tất cả các ñịa chỉ của byte nằm
trong dãy byte biểu diễn.
Một giá trị con trỏ là một hằng ñịa chỉ của một biến hoặc một hàm. Ví
dụ:
int i; &i
là một hằng con trỏ.
Kiểu dữ liệu con trỏ phụ thuộc vào kiểu của biến mà nó trỏ tới. Ví dụ:
int i; &i
là một hằng con trỏ, kiểu
int *
. Có bao nhiêu kiểu dữ liệu thì
cũng có bấy nhiêu kiểu dữ liệu con trỏ tương ứng.
Một biến con trỏ là biến với kiểu giá trị con trỏ.
Dạng chung ñể khai báo biến con trỏ:


13
tên_kiểu_dữ_liệu *tên _biến_con_trỏ;
Ví dụ:
int *pi;

//Khai báo biến
pi
là biến kiểu con trỏ
int

int i;
//khai báo biến
int

pi=&i;
//biến
pi
có giá trị hiện thời là ñịa chỉ của biến
i

Cấp phát ñộng
Các biến mảng, xâu khi ñược khai báo tổng thể sẽ tồn tại trong bộ nhớ
cho tới khi ứng dụng kết thúc. Việc chiếm dụng tài nguyên bộ nhớ có thể dẫn
tới bộ nhớ không còn cho các tác vụ khác trong một ứng dụng phức tạp. Do
ñó, C có cơ chế giúp các biến có thể ñược tạo ra lúc chạy chương trình, tuỳ
theo nhu cầu, do vậy mà số biến này hoàn toàn không ñược xác ñịnh từ trước.
Việc tạo ra biến ñộng và xoá ñi nó (ñể thu hồi bộ nhớ) ñược thực hiện nhờ các
hàm như
malloc()

free()
khai báo sẵn trong thư viện
stdlib.h
. Việc
truy nhập các biến ñộng ñược thực hiện thông qua các biến con trỏ (Pointer

Variable). Các biến con trỏ ñược ñịnh nghĩa như là biến tĩnh (nghĩa là có tên
và ñược khai báo ngay từ ñầu trong phần khai báo biến) và ñược dùng ñể
chứa ñịa chỉ của các biến ñộng.
Hàm cấp phát ñộng cơ bản: khai báo trong thư viện
stdlib.h
(datatype *)malloc(unsigned int size);
Hàm
malloc
xin cấp phát size byte từ bộ nhớ chính cho một ñối tượng,
trả về con trỏ trỏ tới vùng nhớ mới ñược cấp phát hoặc NULL nếu không cấp
phát ñược vùng nhớ. Mẫu
(datatype *)
chính là kiểu con trỏ và ñược hiểu
là chuyển ñổi thành kiểu con trỏ trỏ tới datatype.
void free(void *block);
Hàm này trả lại hệ thống phần bộ nhớ ñã
xin cấp phát từ hàm malloc.
(datatype *)realloc(buf_ptr, newsize);
Hàm cấp phát lại
bộ nhớ trước ñó. Trong ñó:
buf_ptr
là con trỏ ñang trỏ tới vùng ô nhớ ñã
ñược cấp phát từ trước,
newsize
là kích thước mới cần cấp phát, có thể to
hơn hoặc nhỏ hơn.


14
Trong ngôn ngữ C

++
:
C
++
ñã tích hợp hai toán tử
new

delete
ñể thực hiện việc cấp phát
ñộng cho các biến.
Toán tử new và new[ ]
ðể có thể có ñược bộ nhớ ñộng chúng ta có thể dùng toán tử
new
. Theo
sau toán tử này là tên kiểu dữ liệu và có thể là số phần tử cần thiết ñược ñặt
trong cặp ngoặc vuông. Nó trả về một con trỏ trỏ tới ñầu của khối nhớ vừa
ñược cấp phát. Dạng thức của toán tử này như sau:
pointer = new type
hoặc
pointer = new type [elements]
Biểu thức ñầu tiên ñược dùng ñể cấp phát bộ nhớ chứa một phần tử có
kiểu type. Lệnh thứ hai ñược dùng ñể cấp phát một khối nhớ (một mảng) gồm
các phần tử kiểu
type
.
Ví dụ:
int * bobby;
bobby = new int [5];
Trong trường hợp này, hệ ñiều hành dành chỗ cho 5 phần tử kiểu
int


trong bộ nhớ và trả về một con trỏ trỏ ñến ñầu của khối nhớ. Vì vậy lúc này
bobby
trỏ ñến một khối nhớ hợp lệ gồm 5 phần tử
int
.
Bộ nhớ ñộng nói chung ñược quản lí bởi hệ ñiều hành và trong các môi
trường ña nhiệm có thể chạy một lúc vài chương trình có một khả năng có thể
xảy ra là hết bộ nhớ ñể cấp phát. Nếu ñiều này xảy ra và hệ ñiều hành không
thể cấp phát bộ nhớ như chúng ta yêu cầu với toán tử
new
, một con trỏ
null

(zero) sẽ ñược trả về. Vì vậy nên kiểm tra xem con trỏ trả về bởi toán tử
new

có bằng
null
hay không:
int * bobby;
bobby = new int [5];
if (bobby == NULL) {
// Lỗi cấp phát bộ nhớ
};


15
Toán tử delete.
delete pointer;

hoặc
delete [] pointer;
Biểu thức ñầu tiên nên ñược dùng ñể giải phóng bộ nhớ ñược cấp phát
cho một phần tử và lệnh thứ hai dùng ñể giải phóng một khối nhớ gồm nhiều
phần tử (mảng). Trong hầu hết các trình dịch cả hai biểu thức là tương ñương
mặc dù chúng là rõ ràng là hai toán tử khác nhau.
Con trỏ hàm
C cung cấp một kiểu con trỏ hàm dùng ñể tham chiếu tới ñịa chỉ ñiểm
vào của hàm và gọi là con trỏ hàm.
Khai báo:
Kiểu_dữ_liệu(*Tên_biến_con_trỏ_hàm)(Danh_sách_các_ñối);
Gán con trỏ hàm: chúng ta phải gán giá trị của nó bằng ñịa chỉ ñiểm vào
của một hàm thực sự, cách gán:
Tên_biến_con_trỏ_hàm = Tên_hàm;
1.2.2. Sử dụng con trỏ xây dựng cây nhị phân
Một ứng dụng khác của con trỏ và biến ñộng là xây dựng cấu trúc dữ liệu
kiểu cây nhị phân. Chẳng hạn, ta cần xây dựng một cây nhị phân chứa các số
nguyên. Cây gồm các nút chứa các giá trị (số nguyên), mỗi nút có hai nhánh.
Số ñầu tiên ñược ñặt vào một nút gọi là nút gốc. Sau ñó số nguyên ñưa vào
tiếp ñược so sánh với các nút kể từ nút gốc. Nếu lớn hơn hoặc bằng số nguyên
của nút vừa ñặt vào thì nó ñược rẽ sang nhánh bên phải của nút ấy, nếu bé
hơn thì rẽ sang nhánh bên trái.
Khai báo một nút:
struct Tên_nút{
Kiểu_dữ_liệu info;
struct Tên_nút *left, *right;
};
Như vậy, ta thấy cách khai báo này rất giống với khai báo danh sách móc
nối hai chiều: mỗi nút chứa hai con trỏ, con trỏ left dùng ñể trỏ tới cây con



16
bên trái, con trỏ right dùng ñể trỏ tới cây con bên phải, trường info dùng ñể
chứa dữ liệu.
Trong trường hợp này, ta khai báo một nút như sau:
struct Phan_tu{
int Nut;
struct Phan_tu *Phai, *Trai;
};
Ta sử dụng một con trỏ
Root
ñể trỏ ñến gốc của cây nhị phân, một con
trỏ p ñể trỏ ñến từng phần tử. Mô hình chương trình như sau:
Root=calloc(1,sizeof(struct Phan_tu));
Root->Nut=So;
Root->Trai=NULL;
Root->Phai=NULL:
while (So) //chừng nào chưa gặp số 0
{
printf(“Nhập số:”); scanf(“%d”,&So);
p=calloc(1,sizeof(strcut Phan_tu));
p->nut=So;
p->Trai=NULL;
p->Phai=NULL;
Dat_so(p,Root);
}
Trong ñó
Dat_so(p,Root)
là hàm ñặt thêm số p vào cây có gốc Root.
void Dat_so(struct Phan_tu *n1, struct Phan_tu *n2)

{
if(n2==NULL) n2=n1;
else
if(n1->Nut<n2->Nut) Dat_so(n1,n2->Trai);
else Dat_so(n1,n2->Phai) ;
}
Với cách biểu diễn cây nhị phân này, ta có thể dễ dàng sử dụng các phép
duyệt cây như ñã trình bày ở trên.


17
Cây nhị phân còn có ứng dụng ñể tạo cây từ ñiển trong các phần mềm từ
ñiển và ñược ứng dùng nhiều trong các ứng dụng thực tế.
1.3. Vài nét về ngôn ngữ lập trình C và C
++

Ngôn ngữ C do Dennis Ritchie sáng tác ra năm 1972 tại phòng thí
nghiệm Bell Telephone (thuộc công ty viễn thông AT&T của Mĩ) với mục
ñích tương ñối hạn chế: tạo ngôn ngữ ñể viết hệ ñiều hành UNIX. Song nhờ
có các tính ưu việt và tính mềm dẻo nên nó ñã ñược giới tin học nhanh chóng
chấp nhận như là một ngôn ngữ chính thống nhà nghề.
ðến năm 1978, bản in ñầu tiên về ngôn ngữ C ñã ñược in ra thành sách
“The C programming language” do Kernighan và Ritchie viết. C mau chóng
ñược Viện tiêu chuẩn hoá của Mĩ (ANSI: American National Standard
Institute) làm thành tiêu chuẩn với tên gọi “ANSI C” vào năm 1983. Tổ chức
tiêu chuẩn hoá quốc tế ISO (International Standard Organization) cũng xây
dựng chuẩn cho C. May mắn thay cho người dùng là các chuẩn này giống
nhau và ñược biết ñến với cái tên chung là ANSI C.
C là một ngôn ngữ mạnh và mềm dẻo. ðiều hạn chế ñối với C chính là
óc tưởng tượng của người lập trình. C không ñặt ñiều kiện ràng buộc nào cho

người sử dụng. C ñược dùng ñể viết hệ ñiều hành, các trình ñiều khiển, soạn
thảo văn bản, ñồ hoạ, bảng tính… và thậm chí là các chương trình dịnh cho
các ngôn ngữ khác.
C là ngôn ngữ ñược các nhà tin học chuyên nghiệp dùng phổ biến, nhất
là trong việc viết phần mềm hệ thống (hệ ñiều hành, chương trình dịch, soạn
thảo văn bản, cơ sở dữ liệu, bảng tính…). Trong các hệ ñiều hành nổi tiếng
như UNIX, Linux hay Windows thì phần lớn các modul ñều ñược viết bằng
ngôn ngữ C. Một trong các lí do này là tính hiệu quả của chương trình ñược
dịch ra. Một chương trình C khi dịch ra có thể ñạt 80% tính năng của chương
trình ñó viết bằng mã máy. Có khá nhiều chương trình dịch và các thư viện
tiện ích khác cho C có thể khai thác ñược.
C là ngôn ngữ có thể chuyển dịch (portable) hay còn gọi là tính dễ thích
nghi. Tính dễ thích nghi hay tính di chuyển ñược hiểu là chương trình C viết
chi máy tính IBM có thể ñem sang hệ thống máy khác như VAX của công ty


18
Digital cho dịch lại vẫn chạy ñược ngay hoặc sau khi có một vài chỉnh sửa
nhỏ.
C là một ngôn ngữ có ít từ khoá - là các từ dùng riêng cho ngôn ngữ khi
viết chương trình.
C là một ngôn ngữ có tính modul. ðó chính là việc sử dụng các chương
trình con loại hàm (function). Các hàm này có thể sử dụng nhiều lần trong
chương trình hoặc trong chương trình khác. Tuy nhiên, C không cho phép
khai báo hàm trong hàm.
C là ngôn ngữ bậc trung. So với ngôn ngữ bậc cao, một ngôn ngữ bậc
trung không có nghĩa là xấu, là tồi. Bậc trung có nghĩa là khó dùng hơn và ít
ñược phát triển một cách hoàn thiện cho người dùng hơn. C ñược gọi là bậc
trung là vì nó kết hợp ñược các tính năng của ngôn ngữ bậc cao với ngôn ngữ
bậc thấp.

Các ngôn ngữ bậc cao có các kiểu dữ liệu rất dễ dùng. C có 5 kiểu dữ
liệu cơ sở. Nếu xét về phương diện kiểu dữ liệu thì C không ñược mạnh như
Pascal nên cũng khó dùng. Ví dụ, việc trộn lẫn kiểu số nguyên với kiểu kí tự
làm nhiều cho người lúng túng.
C là ngôn ngữ bậc trung nên nó rất mạnh về mặt xử lí bit, byte và xử lí
ñịa chỉ ô nhớ. Vì vậy, C rất thích hợp cho lập trình hệ thống.
ðầu những năm 1980, một tư tưởng lập trình mới ñược ñưa ra dựa trên
việc tổ chức chương trình thành các lớp, phương pháp này ñã thay ñổi hẳn
phương pháp lập trình cấu trúc truyền thống, ñó chính là lập trình hướng ñối
tượng. Các ngôn ngữ lập trình cũng ñược thiết kế lại ñể ñáp ứng ñược phương
pháp lập trình mới. ðể ñưa C vào thế giới hướng ñối tượng, năm 1980 Bjanre
Stroustrup ñã cho ra ñời một ngôn ngữ C mới có tên ban ñầu là “C có lớp, sau
ñó ñến năm 1983 thì gọi là C
++
. Ngôn ngữ C
++
là một sự phát triển mạnh mẽ
của C. C
++
chẳng những ñưa tất cả các khái niệm, công cụ của lập trình hướng
ñối tượng mà còn ñưa vào nhiều khả năng mới mẻ cho hàm. Như vậy, C
++

một ngôn ngữ lai cho phép tổ chức chương trình theo các lớp và các hàm. Có
thể nói, C
++
ñã thúc ñẩy ngôn ngữ C vốn ñã rất thuyết phục ñi vào thế giới lập
trình hướng ñối tượng và C
++
ñã trở thành ngôn ngữ hướng ñối tượng nổi bật

trong những năm 90.


19
1.4. Vài nét về ngôn ngữ lập trình Visual Basic
Visual Basic là gì? Phần "Visual" ñề cập ñến phương pháp ñược sử dụng
ñể tạo giao diện ñồ họa người dùng (Graphical User Interface - GUI) . Có sẵn
những bộ phận hình ảnh, gọi là controls, bạn tha hồ sắp ñặt vị trí và quyết
ñịnh các thuộc tính của chúng trên một khung màn hình, gọi là form. Nếu bạn
ñã từng sử dụng chương trình vẽ chẳng hạn như Paint, bạn ñã có sẵn các kĩ
năng cần thiết ñể tạo một GUI cho Visual Basic.
Phần "Basic" ñề cập ñến ngôn ngữ BASIC (Beginners All-Purpose
Symbolic Instruction Code), một ngôn ngữ lập trình ñơn giản, dễ học, ñược
chế ra cho các khoa học gia (những người không có thì giờ ñể học lập trình
ñiện toán) dùng.
Người mang lại phần "Visual" cho VB là ông Alan Cooper. Ông ñã gói
môi trường hoạt ñộng của Basic trong một phạm vi dễ hiểu, dễ dùng, không
cần phải chú ý ñến sự tinh xảo của Windows, nhưng vẫn dùng các chức năng
của Windows một cách hiệu quả. Do ñó, nhiều người xem ông Alan Cooper
là cha già của Visual Basic.
Khi viết một chương trình trong Visual Basic, ta phải qua hai bước: thiết
kế giao diện và viết lệnh. Khi thiết kế giao diện, ta sử dụng các công cụ do
Visual Basic cung cấp sẵn. Các công cụ này cho phép thiết kế giao diện bằng
chuột lẫn bàn phím.
Visual Basic ñã ñược Microsoft phát triển qua nhiều phiên bản và ngày
càng cung cấp cho người dùng nhiều tính năng mới hữu ích, giúp người lập trình
nhanh chóng viết các chương trình một cách dễ dàng và chuyên nghiệp. ðến
nay, Visual Basic ñã phát triển ñến phiên bản 2005 (nằm trong bộ Microsoft
Visual Studio 2005) với nhiều tính năng mới rất hấp dẫn. Visual Basic 2005 ñã
hoàn toàn là hướng ñối tượng, tức là nó cho dùng lại các lớp (class), form theo

cách kế thừa thật thoải mái. Tuy nhiên, do Microsoft vẫn giữ nguyên tắc dấu và
làm sẵn (của VB6) những gì rắc rối phía sau sân khấu ñể ta có thể tập trung vào
việc tìm kiếm một giải pháp, thay vì quá bận tâm vào cách thức làm một việc gì.
Chính nguyên tắc ấy ñã giúp Microsoft chiêu mộ ñược trên 3 triệu VB
programmers trên khắp thế giới. Visual Basic 2005 cống hiến cho VB
programmers một công cụ rất hữu hiệu ñể dùng cho mọi hoàn cảnh, từ database,
desktop, distributed, internet cho ñến real-time hay mobile (pocket PC).


20
Những ưu ñiểm của Visual Basic 2005 ñến từ chức năng của .NET
Framework 2.0, nó mang ñến phương tiện lập trình như XML, Remoting,
Streaming, Serialisation, Threading… Common Language Runtime (CLR) là
trung tâm ñiểm của .NET Famework, nó là hầm máy ñể chạy các năng tính
của .NET. Trong .NET, mọi ngôn ngữ lập trình ñều ñược dịch ra Microsoft
Intermediate Language (IL) giống như byte code của Java. Nhờ bắt buộc mọi
ngôn ngữ ñều phải dùng cùng các kiểu dữ liệu (gọi là Common Type System)
nên Common Language Runtime có thể kiểm soát mọi giao diện, gọi giữa các
thành phần và cho phép các ngôn ngữ có thể hợp tác nhau một cách thông
suốt. Tức là trong .NET, chương trình VB.NET có thể thừa kế từ chương trình
C# và ngược lại một cách hoàn toàn tự nhiên.
Visual Basic 2005 khắc phục những giới hạn về ñối tượng (Object
Oriented) của VB6 và mang ñến cho ta một ngôn ngữ lập trình hoàn toàn
hướng ñối tượng. Gần như mọi thứ trong Visual Basic 2005 ñều có liên hệ
với Object. Một ưu ñiểm nữa, Visual Basic 2005 hỗ trợ rất tốt tiếng Việt
Unicode, tất cả các thành phần của ứng dụng như form, button, label,
messagebox, … ñều ñược hỗ trợ tối ña. Người lập trình sẽ không còn phải vất
vả khi muốn hiển thị chính xác tiếng Việt cũng như các ngôn ngữ khác trong
giao diện chương trình.
Việc sử dụng Visual Basic 2005 sẽ giúp người lập trình có ñược những

chương trình có giao diện ñẹp, ñáp ứng tốt những nhu cầu của người sử dụng
mà không mất quá nhiều thời gian và công sức.


21
Chương 2. CÁC KHÁI NIỆM CƠ BẢN
Trong các hệ thống truyền tin rời rạc, khi truyền các tín hiệu liên tục, tin
tức thường phải thông qua một số phép biến ñổi: ñổi thành số (thường là số
nhị phân) rồi mã hoá; ở ñầu thu tín hiệu thông qua những phép biến ñổi ngược
với các phép biến ñổi trên: giải mã, liên tục hoá… ñể thu hồi tin tức.
Việc mã hoá tin tức nhằm mục ñích tăng hiệu quả và ñộ tin cậy của hệ
thống truyền tin, nghĩa là tăng tốc ñộ truyền tin và khả năng chống nhiễu.
Thông thường tốc ñộ lập tin thường còn rất xa mới ñạt ñược thông lượng của
kênh. ðể tăng tốc ñộ lập tin, dùng phép mã hoá ñể thay ñổi tính chất thống kê
của nguồn, nhờ ñó có thể tiếp cận với thông lượng của kênh. Trường hợp
kênh có nhiễu, vấn ñề cần phải quan tâm là làm thế nào ñể tăng ñộ chính xác
của việc truyền tin, nghĩa là sai nhầm xảy ra là tối thiểu. Vấn ñề này cũng có
thể ñược cải tiến bằng cách mã hoá
Tóm lại, hai nhiệm vụ lớn mà việc mã hoá cần phải ñạt ñược là: tăng
hiệu suất truyền tin và tăng ñộ tin cậy. Từ ñây dẫn ñến hai hướng lớn cần
nghiên cứu của việc mã hoá là: mã hoá nén dữ liệu và mã hoá có khả năng
phát hiện sai và sửa sai.
Chương này giới thiệu một số khái niệm cơ bản về mã hoá, các phương
pháp biểu diễn mã, các khái niệm về nén dữ liệu và mã hoá có khả năng phát
hiện sai và sửa sai.
2.1. ðịnh nghĩa và các khái niệm về mã hoá
2.1.1. ðịnh nghĩa
Mã hoá nguồn tin X theo bộ mã M là phép ánh xạ 1:1 biến ñổi một tin
x
i


X thành một tổ hợp các ký hiệu của bộ mã M.
Nguồn X = {x
1
,x
2
,…,x
n
}
Bộ mã M = {m
1
,m
2
,…,m
k
}


22
Trong ñó k là cơ số của bộ mã. Ví dụ: k = 2 là mã nhị phân, k = 10
là mã thập phân, k = 16 là mã thập lục phân.
Nếu tin x
i
ñược mã hoá thành: x
i
↔ m
r1
m
r2
…m

rl

Ở ñây l là số ký hiệu của bộ mã dùng ñể biểu diễn x
i
ñồng thời l
cũng là ñộ dài của từ mã.
Ví dụ:
Nguồn X = {x
1
,x
2
,…x
4
}
Bộ mã nhị phân M = {0,1}
Mã hoá x
1
= 00, x
2
= 01, x
3
= 10, x
4
= 11.
2.1.2. Một số khái niệm cơ bản về mã hoá
a. Chiều dài từ mã
Chiều dài từ mã là số kí hiệu của bộ mã dùng ñể mã hoá cho từ mã ñó.
[12] Ví dụ: từ mã 0011001 dùng 7 ký hiệu của bộ mã nhị phân nên có chiều
dài là 7
b. Trọng lượng từ mã

Trọng lượng từ mã là tổng số các ký hiệu khác 0 của từ mã. Ký kiệu:
w(W
i
) là trọng lượng từ mã W
i
. [12]
Ví dụ: Từ mã 0011001 có trọng lượng từ mã là 3
c. Quãng cách mã
Quãng cách mã là số ký hiệu khác nhau tính theo vị trí tương ứng của 2
từ mã có chiều dài bằng nhau.
Gọi W
1
,W
2
là 2 từ mã có chiều dài bằng nhau.
Quãng cách mã d(W
1
,W
2
)=w(W
1

W
2
) với

là phép toán cộng modul
2.
Ví dụ: W
1

= 0011001, W
2
= 1011101 thì d(W
1
,W
2
) = w(W
1

W
2
)=2
Quãng cách của một bộ mã ñược ñịnh nghĩa là quãng cách mã tối thiểu
của hai từ mã bất kỳ của bộ mã. [12]


23
2.1.3. Các phương pháp biểu diễn mã
2.2.2.1. Phương pháp liệt kê
ðây là cách biểu diễn ñơn giản nhất: liệt kê trong một bảng những tin
của nguồn và chỉ rõ các từ mã tương ứng.
Ví dụ:
Nguồn tin A = {a
1
, a
2
, a
3
, a
4

, a
5
}, các lớp tin của nó ñược mã hoá như
bảng 2.1.
Tin a
1
a
2
a
3
a
4
a
5

Từ mã 00 01 100 1000 1001
Bảng 2.1. Bảng mã các tin trong nguồn tin A
Cách biểu diễn này tuy rõ ràng nhưng không thích hợp cho trường hợp
bộ mã lớn và cồng kềnh.
2.2.2.2. Phương pháp mặt phẳng toạ ñộ của mã
Phương pháp này chỉ thích hợp cho các loại mã có trọng số. Dựa vào hai
thông số là ñộ dài n và trọng số b của từ mã ñể lập nên một mặt phẳng toạ ñộ.
Mỗi từ mã ñược biểu diễn bằng một ñiểm trên mặt phẳng toạ ñộ (n, b). Nếu từ
mã v = (v
0
, v
1
, …v
n
) ñược mã hoá bởi bộ mã M có cơ số là m: v

1

M và v
i
=0,
1,…, m-1 với i = 1, 2,…, n. Trong ñó quy ước vị trí ñầu tiên bên trái ứng với
kí hiệu v
1
là vị trí có trọng số nhỏ nhất: m
0
, vị trí thứ i tính từ trái sang phải
ứng với kí hiệu v
i
có trọng số là m
i-1
, vị trí cuối cùng (thứ n) tương ứng với v
n

có trọng số là m
n-1
. Khi ñó, trọng số b của từ mã là tổng trọng số các kí hiệu
trong từ mã ñược tính theo công thức sau:

=

=
n
i
i
i

mvb
1
1

Trong ñó:
v
i
: giá trị của kí hiệu thứ i trong từ mã, v
i

M
i: số thứ tự của kí hiệu trong từ mã, i = 1,…, n
m: cơ số của mã


24
Ví dụ:
Trọng số của từ mã 1011 bằng:
b = 1 x 2
0
+ 0 x 2
1
+ 1 x 2
2
+ 1 x 2
3
= 13
Như vậy mỗi từ mã ñược biểu diễn bằng một ñiểm duy nhất có toạ ñộ là
(n, b).
Bộ mã 00, 01, 100, 1010, 1011 tương tự ví dụ trên ñược biểu diễn trong

bảng 1.2. (với quy ước kí số càng bên trái càng có trọng số nhỏ).
















Hình 2.1. Biểu diễn một bộ mã trên mặt phẳng toạ ñộ
2.2.2.3. Phương pháp cây
Cây gồm có nút lá, nút gốc và các nút trung gian. Gốc của cây gọi là nút
gốc (mức 0). Từ một nút không phải là nút lá có thể phát ñi tối ña m nhánh
(tương ứng với cơ số m) hoặc ít hơn, mỗi nhánh mang một giá trị và kết thúc
ở nút mức i+1. Nút lá biểu diễn cho một từ mã mà thứ tự các giá trị kí hiệu ñi
từ nút gốc ñến nút lá qua các nút trung gian.
Ví dụ: Cây mã cho bộ mã 00, 01, 100, 1010, 1011 ñược biểu diễn trên hình
2.2. Từ cây mã, có thể nhận biết mã ñã cho là loại mã ñều hay không ñều, loại
1 2 3 4
a
4


14

13

12

11

10

9

8

7

6

5

4

3

2

1

0



a
5

a
3

a
2

a
1

×