Dưới đõy, ta sẽ trỡnh bày một số thuật toỏn tớnh bao đúng đó được đề xuất, cựng với một vài phõn tớch và cỏc vớ dụ minh họa đi kốm để thấy rừ bài toỏn tớnh bao đúng XF đó được cộng đồng nghiờn cứu về mụ hỡnh cơ sở dữ liệu quan hệ quan tõm nhiều như thế nào.
------------------------------------------------------------------------------------------------ Thuật toỏn 3.1. Thuật toỏn chuẩn tớnh bao đúng
------------------------------------------------------------------------------------------------ INPUT: , F, X OUTPUT: Bao đúng X+ begin X+ = X; repeat for each (Y Z) in F do if Y X+ then X+ = X+ Z;
until khụng cũn thuộc tớnh nào được thờm vào X+;
return(X+); end;
______________________________________________________________
Bản chất của thuật toỏn 3.1 là ban đầu khởi tạo X+ = X, sau đú tiến hành duyệt từng phụ thuộc hàm trong F, nếu cú phụ thuộc hàm nào cú vế trỏi là tập con của X+ và vế phải khụng là tập con của X+ thỡ bổ sung vế phải của
phụ thuộc hàm này vào X+. Quỏ trỡnh duyệt tập F và thực hiện tương tự được lặp lại cho đến khi khụng cũn thuộc tớnh nào được thờm vào X+.
Vớ dụ 3.1. Cho lược đồ quan hệ S = <, F> trong đú F = {A D, AB E,
BI E, CD I, E C}. Tớnh bao đúng của tập thuộc tớnh X = ABE theo thuật toỏn 2.1.
Ban đầu: X+ = X = ABE. Duyệt tập F lần thứ nhất: X+ = ABE D E
C = ABEDC. Duyệt tập F lần thứ hai: X+ = ABEDC I = ABEDCI. Duyệt tập F lần thứ ba: X+ = ABEDCI E = ABEDCI. Duyệt tập F lần thứ tư:
khụng cú phụ thuộc hàm nào được sử dụng để bổ sung vế phải vào X+ nờn
thuật toỏn kết thỳc và X+ = ABEDCI.
Thuật toỏn 3.2 dưới đõy cũng tương tự thuật toỏn 3.1 nhưng dễ cài đặt
hơn, điều kiện để thuật toỏn dừng và cho kết quả là NEWX = OLDX, điều kiện này cụ thể hơn điều kiện dừng trong thuật toỏn 3.1 (khụng cũn thuộc tớnh nào được thờm vào X+).
------------------------------------------------------------------------------------------------ Thuật toỏn 3.2 [63]. Tớnh bao đúng
------------------------------------------------------------------------------------------------ INPUT: , F, X
OUTPUT: X+
begin
OLDX := ; NEWX := X; while NEWX OLDX do
begin
OLDX := NEWX;
for each W Z in F do
if NEWX W then NEWX := NEWX Z
end;
return NEWX;
end;
______________________________________________________________
Vớ dụ 3.2. Cho lược đồ quan hệ S = <, F> trong đú F = {A D, AB E,
Ban đầu, khởi tạo OLDX = , NEWX = AE. Lần đầu tiờn duyệt F: A D được dựng để bổ sung D vào NEWX, E C được dựng để bổ sung C vào NEWX. Kết thỳc lần duyệt F đầu tiờn, ta cú OLDX = AE và NEWX = AE D
C = AEDC. Lần thứ hai duyệt F: OLDX = AEDC, chỉ cú CD I làm thay
đổi NEWX, NEWX = AEDC I = AEDCI. Lần duyệt F thứ ba: ta thấy OLDX = AEDCI và khụng cú phụ thuộc hàm làm thay đổi NEWX, nghĩa là NEWX = OLDX. Do đú, thuật toỏn kết thỳc và X+ = NEWX = AEDCI.
Dễ chứng minh được rằng độ phức tạp thời gian của hai thuật toỏn trờn là
O(n.p.min{n,p}) trong đú n là số thuộc tớnh trong và p là số phụ thuộc hàm trong F. Như vậy, cỏc thuật toỏn 3.1 và 3.2 khụng là tuyến tớnh theo tớch np.
Cỏc thuật toỏn 3.3, 3.4, 3.5 sau đõy sử dụng một số cấu trỳc dữ liệu nhằm
giảm chi phớ của việc duyệt cỏc tập F và và như vậy giảm chi phớ khi tớnh X+. Cỏc chiến lược rỳt gọn bao gồm:
- Dựng một tập để lưu giữ cỏc thuộc tớnh cũn phải thờm vào bao đúng.
- Dựng một mảng được đỏnh chỉ số bởi cỏc thuộc tớnh Ai để lưu giữ cỏc phụ thuộc hàm cú vế trỏi chứa Ai.
- Lưu giữ số thuộc tớnh thuộc vế trỏi của mỗi phụ thuộc hàm cũn chưa cú mặt trong bao đúng.
Cỏc chiến lược này đó giỳp cỏc nhúm tỏc giả xõy dựng được cỏc thuật
toỏn tuyến tớnh tớnh bao đúng, tức cú độ phức tạp thời gian là O(n.p).
------------------------------------------------------------------------------------------------ Thuật toỏn 3.3 [8]. Thuật toỏn tớnh bao đúng của Beeri
------------------------------------------------------------------------------------------------ INPUT: , F, X OUTPUT: Bao đúng X+ begin for i = 1 to n do AttrList[i] = ; for j = 1 to p do if Ai FDj.lsh then AttrList[i] = AttrList[i] {j}; end if;
end for; end for; for j = 1 to p do Counter[j] = |FDj.lhs|; end for; X+ = X; AddedAttr = X; while (AddedAttr ) do
AddedAttr = AddedAttr - Ai; for each j AttrList[i] do
Counter[j] = Counter[j] - 1; if (Counter[j] = 0) then
AddedAttr = AddedAttr (FDj.rhs - X+);
X+ = X+ FDj.rhs; end if;
end for each; end while;
return(X+); end;
______________________________________________________________ Trong thuật toỏn 3.3, cỏc thuộc tớnh trong tập được đỏnh chỉ số từ 1
tới n, nghĩa là = {A1, A2,..., An}, cỏc phụ thuộc hàm trong F được đỏnh chỉ số từ 1 tới p, FDj.lhs và FDj.rhs tương ứng là vế trỏi và vế phải của phụ thuộc hàm thứ j, |FDj.lhs| là số thuộc tớnh ở vế trỏi của phụ thuộc hàm thứ j.
------------------------------------------------------------------------------------------------ Thuật toỏn 3.4. [28] Thuật toỏn tớnh bao đúng của Diederich
------------------------------------------------------------------------------------------------ INPUT: , F, X OUTPUT: Bao đúng X+ begin X+ = X; UPDATE = X; for each Y Z do
COUNT[Y Z] := |Y|;
end for each;
for each thuộc tớnh Ai Xõy dựng LIST[Ai];
while UPDATE do
Chọn và loại bỏ một thuộc tớnh Ai từ UPDATE; for each (Y Z) LIST[Ai];
Giảm COUNT[Y Z]; if COUNT[Y Z] = 0 then
Bổ sung Z vào UPDATE và X+ nếu Z chưa cú trong X+; end if;
end for each; end while;
return(X+); end;
______________________________________________________________
Trong thuật toỏn 3.4, COUNT[Y Z] lưu số thuộc tớnh ở vế trỏi của phụ thuộc hàm Y Z, LIST[Ai] lưu danh sỏch cỏc phụ thuộc hàm cú vế trỏi chứa Ai.
------------------------------------------------------------------------------------------------ Thuật toỏn 3.5. [63] Thuật toỏn tớnh bao đúng của Paredaens và cộng sự ------------------------------------------------------------------------------------------------ INPUT: , F, X OUTPUT: Bao đúng X+ begin X+ = ; XWAIT = X;
for each (VY) F do NOTIN(VY) = |V|; if V = then
XWAIT = XWAIT Y;
end if;
for each A V do
INLFD[A] = INLFD[A] {VY};
end for each; end for each;
while XWAIT do
for each Ak XWAIT do XWAIT = XWAIT - {Ak}; X+ = X+ {Ak};
for each (VY) INLFD(Ak) do NOTIN(VY) = NOTIN(VY) - 1; If NOTIN(VY) = 0 then
XWAIT = XWAIT {Y - X+}; end if;
end for each; end for each; end while;
return(X+); end;
______________________________________________________________
Trong thuật toỏn 3.5, NOTIN(VY) lưu số thuộc tớnh ở vế trỏi của phụ thuộc hàm VY, INLFD[A] lưu danh sỏch cỏc phụ thuộc hàm cú vế trỏi chứa A.
Về cơ bản, cỏc thuật toỏn 3.3, 3.4, 3.5 là giống nhau. Một số ký hiệu trong cỏc thuật toỏn mặc dự khỏc nhau nhưng cú cựng ý nghĩa, chẳng hạn
AddedAttr, UPDATE, XWAIT hoặc Counter, COUNT, NOTIN. Để minh họa
chi tiết cỏc bước thực hiện trong thuật toỏn 3.3 (đại diện cho cả ba thuật toỏn trờn), ta xột vớ dụ sau:
Vớ dụ 3.3. Cho lược đồ quan hệ S = <, F> trong đú F = {A D, AB E,
BI E, CD I, E C}. Tớnh bao đúng của tập thuộc tớnh X = AE theo thuật toỏn 3.3.
Ta cú cỏc thuộc tớnh trong tập là A1 = A, A2 = B, A3 = C, A4 = D, A5 =
E, A6 = I. Cỏc phụ thuộc hàm trong F là FD1 = (A D), FD2 = (AB E), FD3 = (BI E), FD4 = (CD I), FD5 = (E C). Tập cú n = 6 thuộc tớnh
và tập F cú p = 5 phụ thuộc hàm.
Thực hiện tớnh bao đúng của tập X = AE theo thuật toỏn 3.3 như sau:
Đoạn chương trỡnh Kết quả thực hiện
for i = 1 to 6 do AttrList[i] = ; for j = 1 to 5 do if Ai FDj.lsh then AttrList[1] = ; A1 FD1.lsh AttrList[1] = {1} A1 FD2.lsh AttrList[1] = {1, 2} Tương tự, ta tớnh được:
end if; end for; end for; AttrList[3] = {4}, AttrList[4] = {4} AttrList[5] = {5}, AttrList[6] = {3} for j = 1 to 5 do Counter[j] = |FDj.lhs|; end for; Counter[1] = 1, Counter[2] = 2, Counter[3] = 2, Counter[4] = 2, Counter[5] = 1
X+ = X; AddedAttr = X; X+ = AE; AddedAttr = AE;
Đoạn chương trỡnh
while (AddedAttr ) do AddedAttr = AddedAttr - Ai; for each j AttrList[i] do
Counter[j] = Counter[j] - 1; if (Counter[j] = 0) then
AddedAttr = AddedAttr (FDj.rhs - X+);
X+ = X+ FDj.rhs; end if;
end for each; end while; Kết quả thực hiện AddedAttr = AE - A = E AttrList[1] = {1, 2} Counter[1] = 1 - 1 = 0, Counter[2] = 2 - 1 = 1 Từ Counter[1] = 0
AddedAttr = E (D - AE) = ED và X+ = AE D = AED AddedAttr = ED - E = D
AttrList[5] = {5}, Counter[5] = 1 - 1 = 0 Từ Counter[5] = 0
AddedAttr = D (C - AED) = DC và X+ = AED C = AEDC AddedAttr = DC - D = C
AttrList[4] = {4}, Counter[4] = 2 - 1 = 1 AddedAttr = C - C =
AttrList[3] = {4}, Counter[4] = 1 - 1 = 0 Từ Counter[4] = 0
AddedAttr = (I - AEDC) = I và X+ = AEDC I = AEDCI AddedAttr = I - I =
AttrList[6] = {3}, Counter[3] = 2 - 1 = 1.
Do AddedAttr = nờn thuật toỏn kết thỳc và X+ = AEDCI. Bảng 3.1. Minh họa cho vớ dụ 3.3
Dưới đõy, ta xem xột một thuật toỏn tớnh bao đúng hiệu quả của Mora và cộng sự.
------------------------------------------------------------------------------------------------ Thuật toỏn 3.6. [53] Thuật toỏn tớnh bao đúng của Mora và cộng sự
------------------------------------------------------------------------------------------------ INPUT: , F, X OUTPUT: Bao đúng X+ begin Xnew = X; repeat Xold = Xnew;
for each Y Z F do if Y Xnew then
Xnew = Xnew Z; (I)
F = F - {Y Z}; elseif Z Xnew then
F = F - {Y Z}; (II) else
F = F - {Y Z}; (III)
F = F {Y - Xnew Z - Xnew};
end if; end for each;
until ((Xnew = Xold) or (|F| = 0)); return(Xnew);
end;
______________________________________________________________ Thuật toỏn 3.6 và cỏc thuật toỏn tớnh bao đúng của Diederich, Beeri và Paredaens đó được chạy thử nghiệm và cho kết quả được trỡnh bày trong [53], cụ thể như sau: sinh ngẫu nhiờn tập thuộc tớnh , tập phụ thuộc hàm F và tập
con X ; cỏc tập phụ thuộc hàm được sinh ngẫu nhiờn lần lượt cú 25, 50, 75, 100, 125, 150, 175 và 200 phụ thuộc hàm, số lượng cỏc thuộc tớnh ở vế trỏi và vế phải của cỏc phụ thuộc hàm biến đổi từ 1 đến 300, kớch thước của
cỏc tập phụ thuộc hàm từ 50 đến 61770 thuộc tớnh (kớch thước của một tập phụ thuộc hàm F được định nghĩa là tổng cỏc kớch thước của cỏc phụ thuộc
thực hiện thử nghiệm cỏc thuật toỏn 1817 lần. Kết quả thử nghiệm cho thời