V. CĐY TÌM KIẾM NHỊ PHĐN
CHƯƠNG 4: KIỂU DỮ LIỆU TẬP HỢP
IIỊ CẤU TRÚC BẢNG BĂM ( HASH TABL E) 1 Giới thiệu
1. Giới thiệu
TOP
Căi đặt tự điển bằng mảng tốn O(n) bước để thực hiện câc phĩp toân xen, xóa, hoặc kiểm tra phần tử trín một tự điển có n phần tử. Căi đặt bằng danh sâch liín kết cũng có cùng tốc độ năỵ Căi đặt bằng vectơ bit chỉ tốn một hằng thời gian cho cả ba phĩp toân, nhưng ta lại bị giới hạn trong một phạm vi nhỏ của tập hợp số nguyín. Có một kỹ thuật khâc rất quan trọng vă được sử dụng rộng rêi để căi đặt tự điển đó lă băm.
Băm (Hashing) lă một phương phâp tính toân trực tiếp vị trí của mảng lưu trữ phần tử của tập hợp dựa văo giâ trị của phần tử năy (ta còn gọi lă khóa).
Giả sử ta có một mảng gồm B phần tử được đânh số từ 0 đến B-1 vă một tập hợp A muốn lưu trữ văo trong mảng năỵ Như vậy với mỗi phần tử ŸA ta sẽ dựa văo giâ trị khóa của nó để suy ra một số nguyín trong khoảng từ 0 đến B-1 lă vị trí cất giữ khóa năỵ Hay nói câch khâc lă ta chọn một hăm :
h : A 0 .. B -1
x Ġ h (x) lă vị trí của khóa x trong mảng B.
Như vậy khi cần tìm một phần tử x, ta chỉ cần tính h(x); h(x) được gọi lă giâ trị băm của khóa x vă hăm h được gọi lă hăm băm.
Nói chung lă sẽ có nhiều khóa có cùng giâ trị băm. Tức lă với 2 khóa x, y khâc nhau nhưng ta lại có h(x) = h(y). Trường hợp năy được gọi lă đụng độ. Như vậy để sử dụng phương phâp băm ta cần chọn hăm h sao cho ít xảy ra đuụng độ nhất. Hơn nưa ta phải có câch giải quyết khi đụng độ xảy rạ Mảng được dùng trong phương phâp băm được gọi lă bảng băm.
Ví dụ : Hăm h dưới đđy biến đổi một chỗi ký tự thănh số nguyín thuộc 0 .. B-1
Const B = ... ;
Type Index = 0 .. B - 1 ;
ElementType = String [10] ;
Function h ( x : ElementType ) : Index ;
Var i, sum : Integer ; Begin
Sum := 0 ;
For i:=1 to Length(x) do Sum := Sum + Ord[x] ; h := Sum mod B ;
End;
{ Ví dụ minh họa cho hăm băm trín } B = 11
h (‘Windows’) = 10; h (‘QUATTRO’) = 10 ; h (‘EXCEL’) = 6; h (‘VENTURA’) = 10 ; h (‘FOXPRO’) = 5 ;
2. Bảng băm mở ( Open Hash Table ) TOP
Ý tưởng đơn giản để giải quyết đụng độ lă tạo một danh sâch cho câc phần
tử có cùng giâ trị băm. Nếu bảng băm có B phần tử được đânh số từ 0 đến B-1 vă
hăm h lă hăm băm thì tại phần tử k của mảng lă một danh sâch câc phần tử có cùng giâ trị băm lă k. Mỗi một danh sâch như vậy được gọi lă một lớp hay lă một Bucket.
Danh sâch có thể được tổ chức theo bất kỳ câch năo mă chúng ta đê biết. Nhưng số sỗ phần tử trong mỗi lớp lă không xâc định trước nín căi đặc lớp bằng danh sâch liín kết sẽ thích hợp nhất.
Nếu hăm băm rải đều câc khóa thì trung bình ta có N/B phần tử trong mỗi lớp (với N lă số phần tử có trong tự điển vă B lă số phần tử của bảng băm). Như vậy thời gian để thực hiện câc phĩp toân xen, xóa hoặc kiểm tra thănh phần sẽ lă O(1+ N/B). Nếu ta chọn N vă B thích hợp sao cho N/B lă nhỏ thì câc phĩp toân trín bảng băm chỉ mất một hằng thời gian độc lập với N vă B.
Ta nhận thấy rằng mỗi lớp sẽ có số phần tử không nhiềụ Vì vậy, nếu ta dùng B phần tử của bảng băm lăm B chỉ điểm đầu của danh sâch sẽ gđy lêng phí bộ nhớ rất lớn. Vì vậy phần tử đầu của mỗi lớp ta đặt ngay văo trong mảng.
Khai bâo :
Const B = ... ; { số phần tử của bảng băm }
Type ElementType = ... ; { Kiểu phần tử trong tự điển } Index = 0 .. B-1 ; Elementss = ^ Cell ; Cell = Record Data : ElementType; Next : Elements; End;
OHT = array [ 0 .. B-1] of Elements ; Thủ tục khởi tạo OHT rỗng :
Procedure MakeNullOHT (Var D : OHT);
Var i : Integer ; Begin
For i := 0 to B -1 do D[i] := Nil ; End;
Function Member (x : ElementType; D : OHT) : Boolean;
Var p: Elements; Found: Boolean; Begin
Found:= False;
p := D[H(x)] ; { H(x) lă hăm băm tự chọn } While ( p <> Nil) and (Not Found) do
If p^.Data = x then Found:= True
Else p := p^.Next ; Member:= Found;
End;
Thủ tục xen một phần tử văo OHT :
Procedure InsertOHT (x: ElementType; Var D : OHT);
Var Bucket : Index ; t : Elements ; Begin
If Not Member (x, D) then Begin Bucket : = h(x) ; New (t) ; t^.Data := x ; t^.Next := D[Bucket] ; D[Bucket] := t ; End
Else Writeln (‘ Phan tu da ton tai ‘); End;
Thủ tục xóa một phần tử khỏi OHT :
Procedure DeleteOHT (x: ElementType; Var D : OHT);
Var Bucket : Index ; t, p : Elements ; Found : Boolean ; Begin Bucket : = h(x) ; p := D[Bucket] ; If p <> Nil then If p^.Data = x then Begin D [Bucket] := p^.Next ; Dispose (p) ; End Else { p^.Data <> x } Begin t := p ; p := p^.Next ; Found := False ; While ( p <> Nil) and (Not Found) do
If p^.Data = x then Begin
Found:= True ;
Dispose (p) ; End ; Else Begin t := p ; p := p^.Next ; End; End ; { Else } End;