Ví dụ một bảng băm đơn giảnGV : TRẦN HỮU QUỐC THƯ Khóa k sẽ được lưu trữ tại vị trí k mod M M... Vấn đề xung đột khi xử lý bảng băm- Trong thực tế có nhiều trường hợp có nhiều hơn 2 phần
Trang 1Chương 1:
Các thuật toán trên chuỗi
GV : TRẦN HỮU QUỐC THƯ
Trang 21.3 Thuật toán nén chuỗi
+ Trong thực tế khi biểu diễn thông tin là van bản thì máy tính thường dùng bộ mã ASCII, Unicode , … đây
là các bộ mã mà độ dài dãy bít dành cho ký tự luôn là
Trang 31.3Thuật toán nén chuỗi
GV : TRẦN HỮU QUỐC THƯ
Ví dụ: với chuỗi: “This is a book”
Ký tự Dãy bit Ký tự Dãy bit
Trang 41.3 Thuật toán nén chuỗi
Trang 5* Thuật toán xây dựng mã Huffman
GV : TRẦN HỮU QUỐC THƯ
Vdụ: Xét chuỗi sau:
“ a fast runner need never be afraid of the dark”
Thống kê tần suất xuất hiện của các ký tự trong chuỗi
9 5 1 3 7 3 1 1 1 4 1 5 1 1 1 1
Trang 6* Thuật toán xây dựng mã Huffman
6 4
Trang 82.1 Giới thiệu về bảng băm
-Là CTDL trong đó các phần tử của nó được lưu trữ sao cho việc tìm kiếm sẽ được thực hiện bằng
cách truy xuất trực tiếp thông qua từ khóa
Trang 9Ví dụ một bảng băm đơn giản
GV : TRẦN HỮU QUỐC THƯ
Khóa k sẽ được lưu trữ tại vị trí k mod M (M
Trang 10Ví dụ một bảng băm đơn giản
Với các giá trị: 31, 10 , 14, 93, 82, 95,79,18,27
0 1 2 3 4 5 6 7 8 9
10 31 82 93 14 95 46 27 18 79
Trang 11Vấn đề nảy sinh
GV : TRẦN HỮU QUỐC THƯ
Giả sử thêm 55 vào mảng
Trang 123.2 Vấn đề xung đột khi xử lý bảng băm
- Trong thực tế có nhiều trường hợp có nhiều
hơn 2 phần tử sẽ được “băm” vào cùng 1 vị trí
- Hiển nhiên phần tử được “băm” đầu tiên sẽ
chiếm lĩnh vị trí đó, các phần tử sau cần phải
được lưu vào các vị trí trống khác sao cho vấn đề truy xuất và tìm kiếm phải dễ dàng
Trang 13a Làm giảm xung đột
GV : TRẦN HỮU QUỐC THƯ
-Hàm băm cần được sao cho:
-Xác xuất phân bố khoá là đều nhau
- Dễ dàng tính toán thao tác
Thông thường, hàm băm sử dụng các số nguyên
tố (vì xác suất ngẫu nhiên phân bố các số nguyên
tố là đều nhất
Trang 14b Giải quyết xung đột
Trang 15i Sử dụng danh sách liên kết (nối kết)
GV : TRẦN HỮU QUỐC THƯ
-Ý tưởng:”Các phần tử băm vào trùng vị trí được nối vào DS nối kết” tại vị trí đó
Trang 16*Phân tích
PP DSLK có nhiều khuyết điểm:
- Khi có quá nhiều khoá vào cùng vị trí, DSLK thì tại vị trí đó sẽ rất dài => Tăng chi phí tìm kiếm
- Các ô trống còn dư nhiều => lãng phí về
thời gian tìm kiếm và không gian lưu trữ
Trang 17ii Sử dụng PP “Dò tuyến tính”
GV : TRẦN HỮU QUỐC THƯ
-Ý tưởng:”Nếu có 1 khóa bị băm vào vị trí đã có phần tử thì nó sẽ được chèn vào ô trống gần nhất theo phía bên phải (hoặc trái)
Trang 19c Cài đặt xử lý xung đột
GV : TRẦN HỮU QUỐC THƯ
Trang 20i Danh sách liên kết
- Sử dụng DSLK tại mỗi vị trí lưu trữ
- Nếu xảy ra xung đột thì lưu vào cuối DS tại vị trí trùng
Trang 21H
Trang 22const int M = 101; //Kich thuoc bảng băm
LINKLIST HashTable[M]; //bảng băm
Trang 23Khởi tạo bảng băm
GV : TRẦN HỮU QUỐC THƯ
Trang 24Thêm một khoá vào bảng băm
//Hàm băm
int Hash(int key)
{
return (key % M)}
Trang 25Xoá một khoá trong bảng băm
GV : TRẦN HỮU QUỐC THƯ
Trang 26ii Dò tuyến tính
-Khi xảy ra đụng độ thì chèn vào vị trí trống gần nhất
- Ví dụ: chèn dãy: 5 16 7 8 2 4 6 3 13 24 vào mãng băm có 11 vị trí
0 1 2 3 4 5 6 7 8 9 10
24 2 3 4 5 16 7 8 6 13
Trang 27GV : TRẦN HỮU QUỐC THƯ
const int M = 101; //Kich thuoc bảng băm
int HashTable[M]; //bảng băm
Trang 28Khởi tạo bảng băm
Trang 29Thêm một khoá vào bảng băm
GV : TRẦN HỮU QUỐC THƯ
void Insert(int k)
{
//Xác định vị trí của khoá kint pos = Hash(key)
//Kiểm tra đảm bảo vị trí pos là trống
{
pos = Hash (pos + 1);
//Kiểm tra full
}
HashTable[pos] = key;
}
Trang 30Xoá một khoá trong bảng băm
int Delete(int key)
{
int pos = Hash(key); count = 1;
while (HashTable[pos] != key){
pos = Hash(pos + 1 );
count ++;
if (count > M) break;
}
if (count <= M){ HashTable[pos] = -1; return 1; }
return 0 ; //không tìm đựơc khoá
}
Trang 31iii.Băm kép (Duble Hashing)
GV : TRẦN HỮU QUỐC THƯ
-Dò tuyến tính: pos = (pos + 1) % M
u = Hash2 (key)
Trang 32const int M = 101; //Kich thuoc bảng băm
int HashTable[M]; //bảng băm
Trang 33Khởi tạo bảng băm
GV : TRẦN HỮU QUỐC THƯ
Trang 342 Hàm băm
int Hash(int key)
{
return key % M}
int Hash2(int key)
{
return (M-2) – key % (M-2);
}
Trang 35Thêm một khoá vào bảng băm
GV : TRẦN HỮU QUỐC THƯ
void Insert(int k)
int pos = Hash(key)
//Kiểm tra đảm bảo vị trí pos là trống
Trang 36Chương 3: Cây đỏ đen
Trang 373.1 Cây 2-3-4
GV : TRẦN HỮU QUỐC THƯ
+ cây 2-3-4 là cây nhiều nhánh mà mỗi node của
nó có thể có đến bốn node con và ba mục dữ
liệu
Trang 39Ví dụ:
GV : TRẦN HỮU QUỐC THƯ
2 -3 -4 tree
Trang 41Cách chèn nút
GV : TRẦN HỮU QUỐC THƯ
+ Bottom – up: Mở rộng cây về phía gốc,
tách từ dưới lên, tràn node => tách
+ Top – Down: đi từ trên xuống, gặp nút
dầy thì tách, rồi tìm vị trí thích hợp để chèn
Ví dụ: (xem demo)
Trang 42Đánh giá
+ Cây cân bằng
+ Chi phí tìm kiếm là O(log(n))
Trang 432.1 Cây đỏ đen
GV : TRẦN HỮU QUỐC THƯ
Trang 44a Khái niệm cây đỏ đen
-Là cây nhị phân tìm kiếm => cân bằng
làm cơ sở cho sự cân bằng
Trang 452.1 Các tính chất
GV : TRẦN HỮU QUỐC THƯ
(BLACK)
(nghĩa là không có 2 nút đỏ liên tiếp)
-Tại mọi đường đi từ nút gốc đến 1 nút lá
bất kỳ số nút đen trên các đường đi đó luôn
bằng nhau
-Mọi nút NULL đều là nút lá và mang màu
đen
Trang 46Ví dụ:
Trang 47Qui ước
GV : TRẦN HỮU QUỐC THƯ
-Nút gốc luôn có màu đen ( không bắt buộc)
Trang 48b Biểu diễn cây đỏ - đen
typedef struct Node
{
}
Trang 49c Một số thao tác đơn giản (tự viết)
GV : TRẦN HỮU QUỐC THƯ
+ Khởi tạo
+ Kiểm tra rỗng
Trang 50d Xuất cây ra màn hình
void Print(RBTree t)
{
if (isEmpty(t)){
cout<<“Cây rỗng”;
return;
}Print(t.root, 0):
}
Trang 51d Xuất cây ra màn hình (tt)
GV : TRẦN HỮU QUỐC THƯ
void Print(pNode p, int level)
{
if (!p) {
Trang 52}
Trang 53e Chèn một nút vào cây đỏ đen
GV : TRẦN HỮU QUỐC THƯ
một nút như trong cây tìm kiếm nhị phân bình
thường và gán cho nó màu đỏ.
B1 Tìm vị trí thích hợp để chèn khoá K
B2 Phát sinh 1 nút mới có khoá K, màu
đỏ (RED) và gắn liên kết tại vị trí tìm
được
B3 Hiệu chỉnh lại cây nếu có vi phạm
tính chất
Trang 54* Phép quay phải tại y
x
y
γ
Trang 56Hàm quay trái (tương tự cho quay phải)
void LeftRotate(RBTree t, pNode x) {
pNode y = x->pRight;
x->pRight = y->pLeft; //Bên phải x là
if (p->pLeft !=NULL)
p->pLeft ->pParent = x; //cha là x
p->pParent = x->pParent; // cha của x là cha của y
//nếu x là nút gốc
if (x->pParent == NULL)
t.root = y; //gốc mới sẽ là y
β β
Trang 57Hàm quay trái (tt)
GV : TRẦN HỮU QUỐC THƯ
//trường hợp else => x không phải là gốc
//Nếu x là con trái của cha nó
if (x == (x->pParent)->pLeft)
x->pParent->pLeft = y else
x->pParent->pRight = y;
y->pLeft = x;
x ->pParent = y;
}
Trang 58Ví dụ: Chèn một nút vào cây đỏ đen
Lần lượct chèn vào các nút có giá trị:
Trang 59TH1: Cha, bác x đều có màu đỏ
GV : TRẦN HỮU QUỐC THƯ
- Cho cha và bác thành màu đen
-Ông của x thành màu đỏ
(lưu ý: nút gốc qui ước là màu đen)
Trang 60TH2: Bác x đều có màu đen
x là con phải của cha x
Quay trái tại ông của x đồng thời đổi màu cha của x và ông của x
50
80 25
Trang 61GV : TRẦN HỮU QUỐC THƯ
x
Trang 62TH3: x là con trái, cha x là phải
hoặc x là con phải, cha x là trái
Quay trái (phải) tại cha (không đổi màu)
Trang 63GV : TRẦN HỮU QUỐC THƯ
void Insert(RBTree &t, int k)
//y là “bác” của x
y = x->pParent->pParent->pRight;
}
Trang 65//TH2 luôn xảy ra sau đó
X->pParent ->color = BLACK;
X->pParent->pParent->color = RED;
RightRotae(t,x->pParent->pParent);
}
Trang 67f Huỷ một nút trong cây đỏ đen
GV : TRẦN HỮU QUỐC THƯ
Trang 68Tiến trình chung
-Tìm nút là nút có khoá k trong cây
-Tiến hành huỷ z (hoặc huỷ phần tử thế mạng) và
tạo liên kết với các nhánh con của z
-Cân bằng lại cây (nếu cần thiết)
Trang 69Quy ước
GV : TRẦN HỮU QUỐC THƯ
Do khi xoá và cân bằng cây, sẽ có nhiều trường
hợp cần phải xử lý, trong đó có việc kiểm tra nút
là nút NULL?
Giải pháp : thay tất cả các nút NULL bằng 1 nút
đặc biệt, có tên là Null Đây là nút thật sự luôn có
màu đen, các trị của nó (key, trái , phải, cha)
được gán bất kỳ
Trang 70Quy ước
pNode Null;
Int main()
{
Null -> color = BLACK;
Null ->pParent=
Null->pLeft=Null->pRight = NULL;
Null -> Key = 0;
}
Trang 71Phân tích
GV : TRẦN HỮU QUỐC THƯ
Khi nào cần cân bằng lại cây?
+ Khi nút bị xoá là nút có màu đen
Khi cân bằng cần để ý đến sự vi phạm t/c nào?
+ t/c chiều cao cây đen
Trang 72Phân tích
Khi huỷ một nút đen thì chiều cao đen của
nhánh chứa nó sẽ bị sụt giảm 1 đơn vị, ta
có thể:
+ Biến nút đen cùng cấp ở cây con còn lại thành nút đỏ (nếu được)
+ Thực hiện xoay cây để tạo sự cân bằng
=> KL: Kết hợp đổi màu và xoay cây
Trang 73GV : TRẦN HỮU QUỐC THƯ
void Delete(RBTree &t, int k)
Trang 74Xác định nút y là nút cần thực sự xoá
If (z->pLeft ==Null !! z->pRight == Null)
y = z; //z không đủ 2 con => xoáelse
//y chỉ có thể có 1 con
y = SearchStandFor(z);
Trang 75//cha của x là cha của y
//Nếu x là Null vẫn không báo lỗi
x->pParent = y->pParent;
Trang 77GV : TRẦN HỮU QUỐC THƯ
//Kiểm tra cân bằng
Trang 78Cân bằng lại cây sau khi xoá một nút đen
x: đang thiếu đenw: là anh của x
Trang 79γ δ
η ε
Left Rotate Đổi màu
w
mới
Trang 81TH3: w đen con trái w màu đỏ
GV : TRẦN HỮU QUỐC THƯ
C
x
E E
A
γ
η ε
Quay phải tại W
Đổi màu
w mới
Trang 82TH3: w đen con phải w màu đỏ
A
η ε
Quay trái tại cha của x
Đổi màuw
Đỏ/đen
C
γ δ