ĐẠI HỌC THÁI NGUYÊN
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN VÀ TRUYỀN THÔNG
NGUYỄN THỊ MAI LAN
LƯỢC ĐỒ CƠ SỞ DỮ LIỆU CHUẨN HÓA
Ngành: Khoa học máy tính
Mã số: 8.48.01.01
LUẬN VĂN THẠC SĨ KHOA HỌC MÁY TÍNH
Người hướng dẫn khoa học: PGS TSKH NGUYỄN XUÂN HUY
THÁI NGUYÊN - 2020
i
LỜI CAM ĐOAN
Tôi xin cam đoan luận văn này do bản thân tôi thực hiện dưới sự hướng
dẫn khoa học của PGS TSKH Nguyễn Xuân Huy – Viện Công nghệ thông tin.
Các kết quả nghiên cứu được trình bày trong luận văn là trung thực và chưa
từng công bố trong bất kỳ công trình nào khác. Mọi thông tin trích dẫn trong
luận văn đều đã được chỉ rõ nguồn gốc.
Thái Nguyên, tháng 9 năm 2020
Tác giả
Nguyễn Thị Mai Lan
ii
LỜI CẢM ƠN
Tác giả xin được bày tỏ lòng biết ơn Ban Giám hiệu, giảng viên Trường
Đại học Công nghệ thông tin – truyền thông – Đại học Thái Nguyên đã tận tình
giảng dạy và tạo mọi điều kiện thuận lợi cho tác giả trong suốt quá trình học
tập, nghiên cứu và thực hiện luận văn.
Với tình cảm chân thành, tác giả xin được bày tỏ lòng biết ơn, cảm ơn sâu
sắc tới PGS. TSKH Nguyễn Xuân Huy đã tận tình hướng dẫn, giúp đỡ để luận
văn hoàn thành.
Cuối cùng, tác giả xin được gửi lời cảm ơn tới bạn bè, gia đình và đồng
nghiệp đã luôn động viên, giúp đỡ tác giả hoàn thành khóa học.
Thái Nguyên, tháng 9 năm 2020
Tác giả
Nguyễn Thị Mai Lan
iii
MỤC LỤC
LỜI CAM ĐOAN ........................................................................................ i
LỜI CẢM ƠN ............................................................................................ ii
MỤC LỤC ................................................................................................. iii
CÁC KÍ HIỆU ............................................................................................ v
DANH MỤC CÁC BẢNG ........................................................................ vi
MỞ ĐẦU ..................................................................................................... 1
1. Đặt vấn đề ................................................................................................ 1
2. Đối tượng và phạm vi nghiên cứu ........................................................... 4
3. Hướng nghiên cứu ................................................................................... 4
4. Phương pháp nghiên cứu ......................................................................... 4
5. Ý nghĩa khoa học và thực tiễn ................................................................. 5
6. Cấu trúc của luận văn .............................................................................. 5
Chương 1. CÁC KIẾN THỨC CƠ BẢN ................................................. 6
1.1.Quan hệ, bộ, thuộc tính .......................................................................... 6
1.2. Phụ thuộc hàm .................................................................................... 12
1.3. Bao đóng của tập thuộc tính ............................................................... 14
1.4. Phủ ...................................................................................................... 17
1.5. Khóa của lược đồ quan hệ .................................................................. 18
1.6. Các dạng chuẩn 1NF, 2NF, 3NF và BCNF ........................................ 19
1.7. Bảo toàn 3NF bảo toàn phụ thuộc hàm .............................................. 19
Chương 2. CÁC THUẬT TOÁN VỀ CHUẨN HÓA DỮ LIỆU QUAN
HỆ .............................................................................................................. 20
2.1. Các thuật toán đại số quan hệ ............................................................. 20
2.1.1. Phép chọn......................................................................................... 20
2.1.2. Phép chiếu ........................................................................................ 20
2.1.3. Kết nối tự nhiên ............................................................................... 21
2.1.4. Phép hợp .......................................................................................... 22
iv
2.1.5. Phép giao ......................................................................................... 22
2.1.6. Phép trừ ............................................................................................ 23
2.1.7. Phép chia .......................................................................................... 24
2.2. Các thuật toán quản lý phụ thuộc hàm ................................................ 25
2.2.1. Thuật toán tìm phủ thu gọn tự nhiên của tập PTH F ....................... 25
2.2.2. Thuật toán tìm phủ không dư của tập PTH F ................................... 26
2.2.3. Thuật toán tìm phủ thu gọn trái của tập PTH F ............................... 26
2.2.4. Thuật toán tìm phủ thu gọn phải của tập PTH F .............................. 27
2.2.5. Thuật toán tìm phủ thu gọn của tập PTH F ...................................... 28
2.3. Các thuật toán tìm bao đóng ............................................................... 29
2.4. Các thuật toán khóa ............................................................................. 30
Chương 3. CÀI ĐẶT VÀ ỨNG DỤNG .................................................. 30
3.1. Tiếp cận hướng đối tượng cho thiết kế ............................................... 30
3.2. Thiết kế lớp tập hợp Set ...................................................................... 30
3.2.1. Các thuộc tính của lớp Set ............................................................... 30
3.2.2. Các phương thức của lớp Set ........................................................... 30
3.2.3. Các phép toán tập hợp ..................................................................... 33
3.3. Thiết kế lớp lược đồ quan hệ RSC ..................................................... 40
3.3.1. Các thuộc tính của lớp lược đồ quan hệ RSC .................................. 40
3.3.2. Các phương thức của lớp lược đồ quan hệ RSC ............................. 40
KẾT LUẬN ............................................................................................... 65
TÀI LIỆU THAM KHẢO ....................................................................... 66
v
CÁC KÍ HIỆU
KÍ HIỆU Ý NGHĨA
Phần tử a thuộc tập S a S
Phần tử a không thuộc tập S a S
Tập X là tập con thực sự của tập Y X Y
Tập X là tập con của tập Y X Y
X Y Giao của hai tập X và Y
X Y Hiệu của tập X và Y
X Y Hợp của hai tập X và Y
Lượng tử tồn tại
Lượng tử với mọi
PTH Phụ thuộc hàm
K Khóa
LĐ Lược đồ
vi
DANH MỤC CÁC BẢNG
Bảng 1. Quan hệ Bán hàng với 3 khách hàng đầu tiên ................................ 2
Bảng 2. Quan hệ Bán hàng với 4 khách hàng ............................................. 3
Bảng 3. Quan hệ Bán hàng với 4 khách hàng ............................................. 3
Bảng 1.1. Quản lý sinh viên ....................................................................... 8
Bảng 1.2. Bảng quy ước kích thước ............................................................ 8
1
MỞ ĐẦU
1. Lý do lựa chọn đề tài
Năm 1970 Codd đề xuất khái niệm phụ thuộc hàm như một cơ chế quản lý
ngữ nghĩa dữ liệu trong cơ sở dữ liệu quan hệ [8], [9].
Cho tập thuộc tính U. Một phụ thuộc hàm (PTH) trên U là công thức dạng
f: X Y; X, Y U
trong đó ta gọi X là vế trái và Y là vế phải của PTH f.
Cho quan hệ R(U) và một PTH f: X Y trên U. Ta nói quan hệ R thoả
PTH f, hoặc PTH f đúng trong quan hệ R và viết R(f), nếu hai bộ tuỳ ý trong R
giống nhau trên X thì chúng cũng giống nhau trên Y,
R(XY) (u,vR): (u.X = v.X) (u.Y = v.Y)
Nếu f: X Y là một phụ thuộc hàm trên U thì ta nói tập thuộc tính Y phụ
thuộc (hàm) vào tập thuộc tính X, hoặc tập thuộc tính X xác định hàm tập thuộc
tính Y.
Nếu Y không phụ thuộc hàm vào X thì ta viết X ! Y hoặc (XY).
Cho tập PTH F trên tập thuộc tính U. Ta nói quan hệ R(U) thoả tập PTH
F, và viết R(F), nếu R thoả mọi PTH trong F: R(F) ( f F): R(f)
Cho trước tập thuộc tính U, ký hiệu SAT(F) là tập toàn thể các quan hệ
trên U thoả tập PTH F.
Cho tập các quan hệ trên U, ký hiệu FD() là tập các PTH trên U đúng
trong mọi quan hệ của .
Cho tập PTH F trên tập thuộc tính U. Bao đóng của F, ký hiệu F + là tập
nhỏ nhất các PTH trên U chứa F và thoả các tính chất F1 - F3 của hệ tiên đề
Armstrong Ao sau đây [1], [2], [3]:
X, Y, Z U:
2
F1. Tính phản xạ: Nếu X Y thì X Y F +
F2. Tính gia tăng: Nếu XY F + thì XZYZ F +
F3. Tính bắc cầu: Nếu X Y F + và Y Z F + thì X Z F +
Sau đó hàng loạt công trình nghiên cứu đề xuất các dạng chuẩn cho các
lược đồ quan hệ. Một dạng biểu diễn của lược đồ quan hệ được gọi là dạng chuẩn
nếu nó cho phép người quản trị và người khai thác cơ sở dữ liệu đảm bảo được
tính nhất quán và toàn vẹn dữ liệu trong quá trình cập nhật và khai thác cơ sở dữ
liệu [4],[5].
Quá trình chuẩn hoá (do Codd đề nghị 1972) lấy một lược đồ quan hệ và
thực hiện một loạt các kiểm tra để xác nhận nó có thoả mãn một dạng chuẩn nào
đó hay không. Quá trình này được thực hiện theo phương pháp trên xuống bằng
việc đánh giá mỗi quan hệ với tiêu chuẩn của các dạng chuẩn và tách các quan
hệ nếu cần. Lúc đầu, Codd đề nghị ba dạng chuẩn gọi là dạng chuẩn 1, dạng
chuẩn 2 và dạng chuẩn 3. Tất cả các dạng chuẩn này dựa trên các phụ thuộc hàm
giữa các thuộc tính của một quan hệ.
Chuẩn hoá dữ liệu có thể được xem như một quá trính phân tích các lược
đồ quan hệ cho trước dựa trên các phụ thuộc hàm và các khoá chính của chúng
để đạt đến các tính chất mong muốn:
(1) Cực tiểu sự dư thừa và
(2) Cực tiểu các phép cập nhật bất thường.
Đơn giá
Thành tiền
Tên
Số
Bộ
Mã hàng
(nghìn
(nghìn
hàng
lượng
đồng)
đồng)
1
H1
Bút
2
20
10
2
H2
Vở
10
40
4
3
H3
Cặp
1
70
70
Thí dụ, cho quan hệ bán hàng như sau:
3
Bảng 1. Quan hệ Bán hàng với 3 khách hàng đầu tiên
Ta biết, quan hệ Bán hàng các thỏa phụ thuộc hàm sau đây:
Mã hàng Đơn giá
Mã hàng Tên hàng
Mã hàng Đơn giá, Tên hàng
Đơn giá, Số lượng Thành tiền
Nếu khách hàng thứ tư mua vở nhưng bàn tính tiền nạp nhầm dữ liệu thì quan
Bộ
Mã hàng
Tên hàng
Số lượng
1 2 3 4
H1 H2 H3 H2
Bút Vở Cặp Vở
Đơn giá (nghìn đồng) 10 4 70 4
2 10 1 10
Thành tiền (nghìn đồng) 20 40 70 45
hệ Bán hàng có thể có dạng sau:
Bảng 2. Quan hệ Bán hàng với 4 khách hàng
Như vậy, quan hệ Bán hàng tại Bảng 2 chứa dữ liệu không chuẩn. Sự cố này do
bộ 4 gây ra.
Tuy nhiên, có trường hợp sinh ra dữ liệu không chuẩn nhưng ta không thể biết
nguyên nhân tại bộ nào.
Đơn giá
Thành tiền
Tên
Số
Bộ
Mã hàng
(nghìn
(nghìn
hàng
lượng
đồng)
đồng)
1
H1
Bút
2
20
10
2
H2
Vở
10
40
4
Giả sử khách hàng thứ tư cũng mua vở với dữ liệu được nạp như trong Bảng 3.
70
3
H3
Cặp
1
70
5
4
H2
Vở
10
50
4
Bảng 3. Quan hệ Bán hàng với 4 khách hàng
Lúc này ta chỉ có thể nói, quan hệ Bán hàng chứa dữ liệu mâu thuẫn tại bộ 2 và
bộ 4, nhưng ta không biết bộ nào sinh ra mâu thuẫn.
Trong trường hợp này ta nói quan hệ Bán hàng không chuẩn.
Luận văn được tập trung nghiên cưú các dạng chuẩn của lược đồ cơ sở dữ liệu
quan hệ. Vậy trong khuôn khổ khóa luận thạc sĩ, học viên chọn đề tài:
Lược đồ cơ sở dữ liệu chuẩn hóa
2. Đối tượng và phạm vi nghiên cứu
Luận văn tập trung khảo sát các đối tượng liên quan đến các lược đồ cơ
sở dữ liệu quan hệ sau đây:
Lý thuyết phụ thuộc hàm.
Các thuật toán cơ bản xử lý các đối tượng trong lược đồ quan hệ.
Các thuật toán chuẩn hóa lược đồ quan hệ.
3. Hướng nghiên cứu
Nghiên cứu lý thuyết liên quan đến đề tài: Cơ sở dữ liệu quan hệ,
phụ thuộc hàm, các dạng chuẩn, các thuật toán tính bao đóng, khóa,
chuẩn hóa.
Cài đặt các lớp đối tượng quản lý tập hợp, thuộc tính, phụ thuộc
hàm, khóa, các dạng chuẩn 2NF và 3NF.
Thử nghiệm các lược đồ quan hệ.
5
4. Phương pháp nghiên cứu
Trong luận văn học viên dự kiến sử dụng các phương pháp nghiên cứu chính
sau:
Phương pháp nghiên cứu lý thuyết: Tổng hợp tài liệu, hệ thống lại các
kiến thức, tìm hiểu các khái niệm, thuật toán sử dụng trong đề tài.
Phương pháp lập trình hướng đối tượng.
Phương pháp đối sánh.
Phương pháp trao đổi khoa học, lấy ý kiến chuyên gia.
5. Ý nghĩa khoa học và thực tiễn
Việc nghiên cứu đề tài có thể đóng góp thêm một vài chức năng quản lý
ngữ nghĩa dữ liệu thông qua các dạng chuẩn.
Luận văn thiết kế và cài đặt một hệ thống với các chức năng nhập xuất, lưu
trữ, tính bao đóng, khóa của các lược đồ quan hệ và các thuật toán chuẩn
hóa 3NF. Hệ thống có thể được sử dụng để khảo sát và kiểm định các dạng
chuẩn và các quy trình chuẩn hóa lược đồ quan hệ.
6. Cấu trúc của luận văn
Luận văn có cấu trúc gồm:
Phần mở đầu
Phần nội dung
Chương 1. Các kiến thức cơ sở.
Chương 2. Các thuật toán về chuẩn hóa dữ liệu quan hệ
Chương 3. Cài đặt và ứng dụng.
6
CHƯƠNG 1 - CÁC KIẾN THỨC CƠ BẢN
Trong chương 1 này, tôi sẽ giới thiệu một số cơ sở lý thuyết về cơ sở dữ
liệu gồm:
1.1 Quan hệ, bộ, thuộc tính
Định nghĩa
Cho tập hữu hạn U = {A1, A2 , ... , An} khác rỗng (n 1). Các phần tử của U
được gọi là thuộc tính. Ứng với mỗi thuộc tính AiU, i = 1,2,...,n có một tập
chứa ít nhất hai phần tử dom(Ai) được gọi là miền trị của thuộc tính Ai. Gọi D
là hợp của các dom(Ai), i = 1,2,...,n. Một quan hệ R với các thuộc tính U, ký
hiệu là R(U), là một tập các ánh xạ t: UD sao cho với mỗi AiU ta có
là một bộ của quan hệ R. t(Ai)dom(Ai). Mỗi ánh xạ được gọi
Mỗi quan hệ R(U) có hình ảnh là một bảng, mỗi cột ứng với một thuộc tính,
mỗi dòng là một bộ.
Ta ký hiệu t(U) là một bộ trên tập thuộc tính U.
Một quan hệ rỗng, ký hiệu , là quan hệ không chứa bộ nào.
Vì mỗi quan hệ là một tập các bộ nên trong quan hệ không có hai bộ trùng lặp.
Các ký hiệu và một số quy ước
Theo truyền thống của lý thuyết cơ sở dữ liệu chúng ta chấp nhận các quy
định sau đây:
Các thuộc tính được ký hiệu bằng các chữ LATIN HOA đầu bảng chữ A, B,
C,...
Tập thuộc tính được ký hiệu bằng các chữ LATIN HOA cuối bảng chữ X, Y,
Z,...
Các phần tử trong một tập thường được liệt kê như một xâu ký tự, không có
các ký hiệu biểu diễn tập, chẳng hạn ta viết X = ABC thay vì viết
7
X = A, B, C. XY biểu diễn hợp của hai tập X và Y, X Y. Phép trừ hai tập X
và Y được ký hiệu là X\Y, hoặc X-Y.
Một phân hoạch của tập M (thành các tập con rời nhau và có hợp là M), X1,
X2, ..., Xm được ký hiệu là M = X1 | X2 |... | Xm
với ý nghĩa M = X1 X2 ... Xm và Xi Xj = , 1 i, j m, i j.
Các bộ được biểu diễn bằng các chữ Latin thường có thể kèm chỉ số, thí dụ t,
u, v, t1 ...
Với mỗi bộ t trong quan hệ R(U) và mỗi tập con các thuộc tính X U ta ký
hiệu t[X] hoặc t.X là hạn chế của bộ (ánh xạ) t trên tập thuộc tính X.
Ta chấp nhận quy ước tự nhiên là miền trị của mọi thuộc tính chứa ít nhất hai
phần tử. Trong trường hợp một miền trị của thuộc tính chỉ chứa một giá trị
duy nhất thì ta có thể loại bỏ cột tương ứng của thuộc tính đó trong quan hệ.
Ta chấp nhận quy ước sau đây: Mọi cặp bộ t và v trong mọi quan hệ giống
nhau trên miền rỗng các thuộc tính, t. = v..
Hàm Attr(R) cho tập thuộc tính của quan hệ R.
Hàm Card(R) cho lực lượng (số bộ) của quan hệ R.
Trong trường hợp tập thuộc tính U đã cho trước ta có thể viết đơn giản R thay
cho R(U)
Ký hiệu REL(U) là tập toàn thể các quan hệ trên tập thuộc tính U, REL_p(U)
là tập toàn thể các quan hệ có không qúa p bộ trên tập thuộc tính U, p 1.
Hai quan hệ R và S được gọi là tương thích nếu chúng có cùng một tập thuộc
tính, tức là nếu Attr(R) = Attr(S).
Với mỗi bộ t trong quan hệ R(U) và mỗi bộ v trong quan hệ S(V) ta ký hiệu tv
là phép dán hai bộ t và v. tv cho ta bộ r trên tập thuộc tính UV thoả điều kiện:
r.U = t và r.V = v.
Với mỗi bộ t trong quan hệ R(U) và với mỗi quan hệ S(V) ta ký hiệu tS là
phép dán bộ t với quan hệ S. tS cho ta quan hệ P(UV) = { tv | vS }
Thí dụ
8
Trong một trường học, chúng ta quản lý sinh viên theo biểu gồm các thuộc tính
STT
Mã SV
Họ tên SV
Lớp
Khoa
Giới tính
Năm sinh
Quê quán
1
DTS001
Nam
2001
A1
Thái Bình
Toán học
Nguyễn Duy Nam
2
DTS002
Nữ
2001
Phú Thọ
A2
Bùi Minh Hiền
Vật lí
3
DTS003
Nữ
2000
A1
Trần Ngọc Hà
Thái Nguyên
Toán học
…
…
…
…
…
…
130
DTS130
Nam
2001
Hà Nội
A3
Hóa học
Hoàng Mạnh Trung
sau:
Bảng 1.1. Quản lý sinh viên
Ta quy ước kích thước của các thuộc tính như sau:
Tên thuộc tính
Kích thước
Kiểu
STT
Kí tự
3
MASV
Kí tự
8
HOTEN
Kí tự
30
GIOITINH
Kí tự
4
NAMSINH
Số
4
QUE
Kí tự
15
LOP
Kí tự
3
KHOA
Kí tự
15
Bảng 1.2. Bảng quy ước kích thước
9
SINHVIEN={STT,MASV,HOTEN,GIOITINH,NAMSINH,QUE,LOP,KHOA}
Như vậy ta có tập thuộc tính
Ta có ứng với cột Mã SV có DTS01, DTS02…DTS130 là thuộc tính của bảng
Với bản ghi thứ 2(dòng thứ 2) chúng ta có một bộ gồm STT(2), Mã SV(DTS02),
Họ tên SV(Bùi Minh Hiền), Giới tính(Nữ), Năm sinh(2001), Quê quán(Phú
Thọ), lớp(A2), Khoa(Vật lí).
1.2 Phụ thuộc hàm
Định nghĩa
Cho tập thuộc tính U. Một phụ thuộc hàm (PTH) trên U là biểu thức dạng
f: X→Y ; X,Y⊆ U
Nếu f: X→Y là một phụ thuộc hàm trên U thì ta nói tập thuộc tính Y phụ thuộc
vào tập thuộc tính X, hoặc tập thuộc tính X xác định hàm tập thuộc tính Y. X là
vế trái và Y là vế phải của PTH f. Ta cũng dùng hai toán tử LS(f) và RS(f) để xác
định vế trái và vế phải của PTH f, cụ thể là
nếu f: X→ Y thì LS(f) = X, RS(f) = Y.
Cho quan hệ R(U) và một PTH f: X→Y trên U. Ta nói quan hệ R thoả PTH f
và viết R(f), nếu hai bộ tuỳ ý trong R giống nhau trên X thì chúng cũng giống
nhau trên Y.
R(X→Y) (∀ u,v ∈ R): (u.X = v.X) (u.Y = v.Y)
Ta dùng ký hiệu X ↛Y với ý nghĩa tập thuộc tính Y không phụ thuộc hàm vào
tập thuộc tính X[7,8].
Cho tập PTH F trên tập thuộc tính U. Ta nói quan hệ R(U) thoả tập PTH F, và
viết R(F), nếu R thoả mọi PTH trong F
R(F) (∀ f ∈ F): R(f)
10
Nếu quan hệ R thỏa PTH f ta cũng nói PTH f đúng trong quan hệ R.
Thí dụ: Cho quan hệ R(A, B, C, D, E) như sau
P (A B C D E) a 1 x d y a 1 x d x b 2 y 2 x b 2 y 2 y
Và các PTH f1: AA, f2: AB, f3: ACC, f4: AD, f5: DA, f6: AE.
Khi đó các PTH f1 - f5 đúng trong R, mặt khác, R không thỏa PTH f6.
Cho trước tập PTH F trên tập thuộc tính U, ký hiệu SAT(F) là tập toàn thể các
quan hệ trên U thoả tập PTH F, SAT_p(U), p 1 là tập toàn thể các quan hệ
Có không quá p bộ trên U và thoả tập PTH F , cụ thể là
SAT(F) = { R | RREL(U), R(F) }
SAT_p(F) = { R | RREL_p(U), R(F) }
Cho tập các quan hệ trên U, ký hiệu FD() là tập các PTH trên U đúng
trong mọi quan hệ của .
Hệ tiên đề Armstrong
Bao đóng của tập PTH
Định nghĩa
Cho tập PTH F trên tập thuộc tính U. Bao đóng của F, ký hiệu F+ là tập nhỏ
nhất các PTH trên U chứa F và thoả các tính chất F1-F3 của hệ tiên đề
Armstrong Ao sau đây
X, Y, Z U:
F1. Tính phản xạ: Nếu X Y thì XY F +
F2. Tính gia tăng: Nếu XY F + thì XZYZ F +
F3. Tính bắc cầu: Nếu XY F + và YZ F + thì XZ F +
Chú ý :
11
Các PTH có vế trái chứa vế phải như mô tả trong F1 được gọi là tầm thường.
Các PTH tầm thường đúng trong mọi quan hệ. Ngoài ra, các quan hệ trên tập
thuộc tính U có không quá một bộ thỏa mọi PTH trên U.
Một số tính chất của PTH
Cho tập thuộc tính U và các tập phụ thuộc hàm F, G trên U, tập một số quan
hệ trên U, các quan hệ R và S trên U. Dễ dàng chứng minh các tính chất sau
đây:
1. Nếu F G thì SAT(F) SAT(G)
2. SAT(FG) = SAT(F) SAT(G)
3. FD(RS) FD(R) FD(S)
4. R S FD(R) FD(S)
5. F FD(SAT(F))
6. SAT(FD())
7. SAT(FD(SAT(F))) = SAT(F)
8. FD(SAT(FD())) = FD()
Thí dụ
Chứng tỏ FD(RS) FD(R ) FD(S).
Ta chọn U = AB; quan hệ R(U) chứa một bộ duy nhất u = (a,x); quan hệ S(U)
chứa một bộ duy nhất v = (a,y), x y.
R và S thỏa mọi PTH trên U. Quan hệ P = R S chứa 2 bộ u và v. P không thỏa
PTH AB.
Một số tính chất mở rộng của PTH
Sử dụng ba tiên đề Armstrong ta dễ dàng chứng minh các tính chất F4 - F11 sau
đây. Một số tính chất được chia nhỏ nhằm mục đích mô tả các hệ tiên đề khác
cho PTH trong các mục tiếp theo.
X, Y, Z, V U, A U:
F4. Tính tựa bắc cầu: XY, YZV XZV
F5. Tính phản xạ chặt: X X
12
F6. Mở rộng vế trái và thu hẹp vế phải: XY XZY\V
F7. Cộng tính đầy đủ: XY, ZV XZYV
F8. Mở rộng vế trái: XY XZY
F9. Cộng tính ở vế phải: XY, XZ XYZ
F10. Bộ phận ở vế phải: XYZ XY
F11.Tính tích luỹ: XYZ, ZAV XYZA
1.3 Bao đóng của tập thuộc tính
Định nghĩa
Cho tập PTH F trên tập thuộc tính U và một tập con các thuộc tính X trong U.
Bao đóng của tập thuộc tính X, ký hiệu X+ là tập thuộc tính
X+ = {A U | X AF+}
Thuật toán tìm bao đóng của một tập thuộc tính
Cho tập PTH F trên tập thuộc tính U và một tập con các thuộc tính X trong U.
Để xác định bao đóng X+ của tập thuộc tính X ta xây dựng dãy bao nhau
X(0) X(1) … X(i) như sau
Xuất phát: Đặt X(0)=X,
Với i > 0, ta đặt
𝐿→𝑅∈𝐹 𝐿𝑋𝑖
𝑋(𝑖+1) = 𝑋𝑖 ⋃ 𝑅
Nếu X(i+1) = X(i) thì dừng thuật toán và cho kết quả X + = X(i).
Algorithm Closure Format: thuộc tính X của U Output: - Y = X+ = {A U | XA F+} Method Y:=X; repeat
13
Z:=Y; for each FD LR in F do if L Y then Y:=YR; endif; endfor; until Y=Z; return Y; end Closure.
Thuật toán trên có độ phức tạp O(mn2 ).
1.4 Phủ
Định nghĩa
Cho hai tập PTH F và G trên cùng một tập thuộc tính U. Ta nói F suy dẫn ra
được G, ký hiệu F╞ G, nếu gG: F╞ g. Ta nói F tương đương với G, ký hiệu
F G, nếu F╞ G và G╞ F. Nếu F G ta nói G là một phủ của F. Ký hiệu F ≢
G có nghĩa F và G không tương đương. Cho tập PTH F trên tập thuộc tính U và
X là tập con của U, ta dùng ký hiệu XF+ trong trường hợp cần chỉ rõ bao đóng
của tập thuộc tính X lấy theo tập PTH F.
+ Phủ không dư
Định nghĩa: Cho hai tập PTH F và G trên tập thuộc tính U. G được gọi là phủ
không dư
của F nếu
(i) G là một phủ của F, và
(ii) G có dạng không dư theo nghĩa sau: gG: G \{g} ≢ G
Thuật toán tìm phủ không dư của tập PTH
Algorithm Nonredundant Format: Nonredundant(F) Input: - Tập PTH F Output: - Một phủ không dư G của F
14
(i) G F (ii) g G: G\{g} ≢ G Method G:=F; for each FD g in F do If IsMember(g,G\{g})then G:=G\{g}; endif; endfor; return G; end Nonredundant.
+ Phủ thu gọn trái
Định nghĩa: Cho hai tập PTH F và G trên tập thuộc tính U. G được gọi là phủ
thu gọn trái của F nếu
(i) G là một phủ của F, và
(ii) (LRG,AL): G\{LR}{L\AR} ≢ G
Thuật toán tìm phủ thu gọn trái của tập PTH
Để ý rằng AL ta có L\A L, nên
g: LRG,AL): G\{g}{L\AR}╞ LR,
do đó ta chỉ cần kiểm tra G ╞ L\AR ?
Algorithm Left_Reduced Format: Left_Reduced(F) Input: - Tập PTH F Output: - Một phủ thu gọn trái G của F (i) G F (ii) g:LRG,AL: G\{g}{L\AR}≢G Method G:=F; for each FD g:L R in F do X:=L; for each attribute A in X do if IsMember(L\AR,G)then delete A from L in G; endif; endfor;
15
endfor; return G; end Left_Reduced.
+ Phủ thu gọn phải
Định nghĩa: Cho hai tập PTH F và G trên tập thuộc tính U. G được gọi là phủ
thu gọn phải của F nếu
(i) G là một phủ của F, và
(ii) (LRG, AR): G\{LR}{LR\A} ≢ G
Thuật toán tìm phủ thu gọn phải của tập PTH
Algorithm Right_Reduced Format: Right_Reduced(F) Input: - Tập PTH F Output: - Một phủ thu gọn của F Method G:=F; for each FD g:L R in F do H:=G\{LR}; X:=R; for each attribute A in X do if A in Closure(L,H{LR\A})then delete A from R in G; endif; endfor; endfor; return G; end Right_Reduced.
+ Phủ thu gọn
Định nghĩa: Cho hai tập PTH F và G trên tập thuộc tính U. G được gọi là phủ
thu gọn của F nếu G đồng thời là phủ thu gọn trái và thu gọn phải của F.
Thuật toán tìm phủ thu gọn của tập PTH
Algorithm Reduced
16
Format: Reduced(F) Input: - Tập PTH F Output: - Một phủ thu gọn của F Method return Right_Reduced(Left_Reduced(F)); end Reduced
+ Phủ tối thiểu
Định nghĩa: Cho hai tập PTH F và G trên tập thuộc tính U. G được gọi là phủ
tối thiểu của F nếu
(i) G là một phủ thu gọn của F
(ii) Vế phải của mọi PTH trong G chỉ chứa một thuộc tính.
Thuật toán tìm phủ tối thiểu của tập PTH
Algorithm MinCover Format: MinCover(F) Input: - Tập PTH F Output: - Một phủ tối thiểu G của F Method // Tách mỗi PTH LR trong F thành các PTH có // vế phải chỉ chứa một thuộc tính LA, A R G:=; for each FD LR in F do for each attribute A in R\L do if LA not_in G then add LA to G; endif; endfor; endfor; G:=Nonredundant(Left_Reduced(G)); return G; end MinCover.
Thí dụ
17
Cho lược đồ quan hệ R = , Trong đó :
U = {ABC}
F = {A→B, B→A, C→B}
Hãy tìm một khoá tối thiểu K của lược đồ R
Đặt T = {ABC}; P = {AB} ; K = U\P = {C}
Tính thử K +
Ta có K+ = {CBA} = U
Vì K+ = U, nên khóa tối thiểu tìm được là: K = {C} là một khoá của R.
1.5 Khóa của lược đồ quan hệ
Cho LĐQH p = (U,F). Tập thuộc tính K U được gọi là khoá của LĐ p nếu
(i) K + = U
(ii) A K: (K {A})+ U
Hai điều kiện trên tương đương với
(i') K U
(ii') A K: (K {A}) ! U
Nếu K thoả điều kiện (i) thì K được gọi là một siêu khoá.
Thuộc tính A U được gọi là thuộc tính khoá (nguyên thuỷ hoặc cơ sở)
nếu A có trong một khoá nào đấy. A được gọi là thuộc tính không khoá (phi
nguyên thuỷ hoặc thứ cấp) nếu A không có trong bất kỳ khoá nào. Cho LĐQH
(U,F), ta kí hiệu UK là tập các thuộc tính khóa và Uo là tập các thuộc tính
không khóa.
Thí dụ:
Tìm khóa biết: U = ABCDEGF = {B -> C, AC -> D, D -> G, AG -> E}
Đặt: T = { BACDG}- P = {CDGE}- K = U\P
Ta được: K = {AB}, T ∩ P = {CDG}
Tính K+ ta có: K+ = {BEACDG} U
18
Vậy khóa tìm được là: K = {AB}
Chú ý: Trong một số tàì liệu thuật ngữ khoá được dùng theo nghĩa siêu
khoá và thuật ngữ khoá tối tiểu được dùng theo nghĩa khoá.
1.6 Các dạng chuẩn 1NF, 2NF, 3NF và BCNF
LĐQH p = (U,F) được gọi là LĐ
a) dạng chuẩn 1 (1NF) nếu mọi thuộc tính trong U đều không phải là thuộc
tính phức hợp. Chính xác ra là: LĐ p được gọi là LĐ dạng chuẩn 1 nếu chỉ sử
dụng các phép toán quan hệ thì không thể truy nhập đến một thành phần của
một thuộc tính có hơn một thành phần.
b) dạng chuẩn 2 (2NF) nếu p là LĐ 1NF và mọi thuộc tính không khoá đều
phụ thuộc đầy đủ vào mọi khoá,
A Uo , K Key(p) : K + A
c) dạng chuẩn 3 (3NF) nếu p là LĐ 1NF và mọi thuộc tính không khoá đều
phụ thuộc trực tiếp vào mọi khoá,
A Uo , K Key(p) : K * A
d) dạng chuẩn 3 (3NF) nếu p là LĐ 1NF và mọi PTH không tầm thường
XA, A là thuộc tính không khóa đều cho ta X là một siêu khoá,
(X A, A Uo – X ) X + = U
e) dạng chuẩn Boyce-Codd (BCNF) nếu p là LĐ 1NF và mọi thuộc tính
đều phụ thuộc trực tiếp vào mọi khoá,
A U , K Key(p) : K * A
f) dạng chuẩn Boyce-Codd (BCNF) nếu p là LĐ 1NF và mọi PTH không tầm
thường XY đều cho ta X là một siêu khóa.
(X Y, Y – X ) X + = U
Sơ đồ tương quan giữa các dạng chuẩn
BCNF 3NF 2NF
1.7 Bảo toàn 3NF bảo toàn phụ thuộc hàm
19
Algorithm 3NF Function: Chuẩn hóa 3NF không tổn thất và bảo toàn PTH. Input: LĐQH p = (U,F) Output: Các LĐQH 3NF (U1,K1),(U2,K2),...,(Us,Ks) thoả RREL(U): R[U1]R[U2]...R[Us] = R K1, K2,..., Ks - khoá của các lược đồ tương ứng F {F+[Ui] | i = 1,2,...,s} Method 1. Tìm một phủ tối thiểu của F: G = {K1A1, K2A2,..., KmAm} 2. Ghép các PTH có cùng vế trái trong G để thu được phủ G = {K1X1, K2X2,..., KsXs}. 3. /* Xét phép tách = (K1X1,...,KsXs). Nếu chứa một siêu khóa nào đó của p thì return {(K1X1,K1),...,(KsXs,Ks)} nếu không return {(K1X1,K1),...,(KsXs,Ks),(K,K)} với K là một khóa của p. */ construct = (K1X1,K2X2,...,KsXs); for each component V = KiXi in do if V+ = U then // V = KiXi là siêu khóa return {(K1X1,K1),...,(KsXs,Ks)}; endif; endfor; K = Key(U,F); return {(K1X1,K1),...,(KsXs,Ks),(K,K)}; End 3NF
20
CHƯƠNG 2 - CÁC THUẬT TOÁN VỀ CHUẨN HÓA DỮ LIỆU
QUAN HỆ
Trong chương này tôi sẽ trình bày các thuật toán của đại số quan hệ, thuật toán
quản lý phụ thuộc hàm, các thuật toán tìm bao đóng và các thuật toán tìm khóa
gồm các thuật toán sau:
2.1. Các thuật toán của đại số quan hệ
Các thuật toán của đại số quan hệ gồm:
2.1.1 Phép chọn
Algorithm Selection Function: Thực hiện phép Chọn Format: P = R(e) Input: - Quan hệ R(U) - Biểu thức chọn e trên U. Output: - Quan hệ P(U) = R(e) = {tR | Sat(t,e)} Method // Tạo lập quan hệ P tương thích với R
Create(P,Attr(R)); for each tuple t in R with Sat(t,e) do
add t to P ;
endfor; return P;
end Selection.
Độ phức tạp tính toán: Thuật toán duyệt r bộ, phép kiểm tra Sat(t, e) kiểm tra
trên n thuộc tính, tổng cộng cần O(n.r) phép kiểm tra. [1,2]
2.1.2 Phép chiếu
Algorithm Projection Function: Thực hiện phép Chiếu Format: P = R[X] Input: - Quan hệ R(U) - Tập con thuộc tính X của U.
21
Output: - Quan hệ R[X]={t.X | tR} Method Create(P,X); for each tuple t in R with t.X not_in P do add t.X to P ; endfor;
return P;
end Projection.
Độ phức tạp tính toán: Giả sử mỗi lần thuật toán chỉ nạp được 1 bộ vào quan
hệ kết quả P. Để kiểm tra bộ t.X có trong P ta cần tối đa r phép so sánh theo n
thuộc tính. Vậy độ phức tạp tính toán là O(n.r2). [1,2]
2.1.3 Kết nối tự nhiên
Algorithm Join Function: Thực hiện phép Kết nối tự nhiên hai quan hệ. Format: P = RS Input: - Quan hệ R(U) - Quan hệ S(V) Output: - Quan hệ RS={uv | uR,vS,u.M = v.M, M = U v} Method X = Attr(R) Attr(S); M = Attr(R) Attr(S); Create(P,X); for each tuple u in R do for each tuple v in S with (u.M = v.M) do add uv to P ; endfor; endfor; return P; end Join.
22
Độ phức tạp tính toán: Giả sử hai quan hệ R và S có k thuộc tính chung, khi đó
độ phức tạp tính toán sẽ là O(r.s.k) thao tác trên bộ. [1,2]
2.1.4 Phép hợp
Algorithm Union Function: Thực hiện phép Hợp hai quan hệ Format: P = R+S Input: - Quan hệ R(U) - Quan hệ S(U) Output: - Quan hệ R+S = {t | tR tS} Method P := R; for each tuple v in S with (v not_in R) do add v to P ; endfor; return P; end Union.
Độ phức tạp tính toán: Phép kiểm tra v thuộc R đòi hỏi r lần duyệt và so sánh
trên n thuộc tính. Vậy độ phức tạp tính toán sẽ là O(s.r.n) thao tác trên bộ. [1,2]
2.1.5 Phép giao
Algorithm Intersection Function: Thực hiện phép giao hai quan hệ Format: P = R & S Input: - Quan hệ R(U) - Quan hệ S(U) Output: - Quan hệ R & S = { t | t R t S } Method
Create(P,Attr(R)); for each tuple u in R with (u in S) do add u to P; endfor; return P;
end Intersection.
Độ phức tạp tính toán: O(s.r.n). [1,2]
23
2.1.6 Phép trừ
Algorithm Substraction Function: Thực hiện phép Trừ hai quan hệ Format: P = R-S Input: - Quan hệ R(U) - Quan hệ S(U) Output: - Quan hệ R - S = {t | t R t S} Method
Create(P,Attr(R)); for each tuple u in R
with (u not_in S) do add u to P;
endfor;
return P;
end Substraction.
Độ phức tạp tính toán: O(s.r.n). [1,2]
2.1.7 Phép chia
Algorithm Division Function: Thực hiện phép Chia hai quan hệ Format: P = R:S Input: - Quan hệ R(U) - Quan hệ S(V) Output: Quan hệ R:S = {t.M | tR,(t.M)S R, M = U-V} Method
M = Attr(R)-Attr(S); c := Card(S);//số bộ của S Create(P,M); for each tuple t in R with (t.M not_in P) do
d := 0;//khởi tạo biến đếm for each tuple v in S if (t.M)v in R then d := d + 1
else breakfor;
endif; endfor; if d = c then add t.M to P;
24
endif; endfor; return P;
end Division.
Độ phức tạp tính toán: Thuật toán duyệt r bộ của quan hệ R. Phép kiểm tra t.M
thuộc P đòi hỏi r lần duyệt và so sánh trên n thuộc tính. Tiếp đến là duyệt s lần
các bộ v của quan hệ S và kiểm tra (t.M)*v có trong R. Vậy độ phức tạp tính toán
sẽ là O(r2.s.n) thao tác trên bộ. [1,2]
2.2. Các thuật toán quản lý tập phụ thuộc hàm.
Các thuật toán quản lý phụ thuộc hàm gồm:
2.2.1 Thuật toán tìm phủ thu gọn tự nhiên của tập PTH F.
Định nghĩa: Cho hai tập PTH F và G trên cùng một tập thuộc tính U. G là phủ
thu gọn tự nhiên của F nếu
1. G là một phủ của F, và
2. G có dạng thu gọn tự nhiên theo nghĩa sau:
2a. Hai vế trái và phải của mọi PTH trong G rời nhau (không giao nhau.)
f G: LS(f) RS(f) =
2b. Các vế trái của mọi PTH trong G khác nhau đôi một.
f, g G: f g LS(f) LS(g)
Thuật toán
Algorithm Natural_Reduced Function: Tính phủ thu gọn tự nhiên của tập PTH Format: Natural_Reduced(F) Input: - Tập PTH F
Output: - Một phủ thu gọn tự nhiên G của F
(i) G F (ii) LR G: L R = (iii) LiRi,LjRjG: ij LiLj
Method
G := ; for each FD L R in F do
Z := R - L;
25
if Z then
if there is an FD L Y in G then
replace L Y in G by L
YZ
else add L Z to G;
endif;
endif; endfor; return G;
end Natural_Reduced.
Độ phức tạp của thuật toán: Trong [2] độ phức tạp của thuật toán là O(mn) với
m là số lượng PTH trong tập F và n là số lượng thuộc tính trong U. [1.2]
2.2.2 Thuật toán tìm phủ không dư của tập PTH F.
Định nghĩa: Cho hai tập PTH F và G trên tập thuộc tính U. G được gọi là phủ
không dư của F nếu
(i) G là một phủ của F, và
(ii) G có dạng không dư theo nghĩa sau: gG: G \{g} ≢ G
Thuật toán
Algorithm Nonredundant Function: Tính phủ không dư
Format: Nonredundant(F) Input: - Tập PTH F
Output: - Một phủ không dư G của F
(i) G F (ii) g G: G-{g} ! G Method U := Attr(F); // Tập thuộc tính của F G := F;
for each FD g: L R in F do
if R Closure(U,G-{g},L) then
G := G – {g};
endif; endfor; return G;
26
end Nonredundant.
2.2.3 Thuật toán tìm phủ thu gọn trái của tập PTH.
Định nghĩa: Cho hai tập PTH F và G trên tập thuộc tính U. G được gọi là phủ
thu gọn trái của F nếu
(i) G là một phủ của F, và
(ii) (LRG,AL): G\{LR}{L\AR} ≢ G
Thuật toán
Để ý rằng AL ta có L\A L, nên
g: LRG,AL): G\{g}{L\AR}╞ LR,
do đó ta chỉ cần kiểm tra G ╞ L\AR ? [1,2]
Algorithm Left_Reduced Function: Tính phủ thu gọn trái của tập PTH Format: Left_Reduced(F) Input: - Tập PTH F Output: - Một phủ thu gọn trái G của F
(i) G F (ii) g:LR G,AL: G-{g}{L-{A}R}!G Method U := Attr(F);// Tap thuoc tinh cua F G := F; for each FD g:L R in F do
X := L;
for each attribute A in X do if R Closure(U,G,L-{A}) then
delete A from L in G;
endif; endfor; endfor; return G; end Left_Reduced.
2.2.4 Thuật toán tìm phủ thu gọn phải của tập PTH F.
27
Định nghĩa: Cho hai tập PTH F và G trên tập thuộc tính U. G được gọi là phủ
thu gọn phải của F nếu
(i) G là một phủ của F, và
(ii) (LRG, AR): G\{LR}{LR\A} ≢ G
Thuật toán
Algorithm Right_Reduced Function: Tính phủ thu gọn phải của tập PTH Format: Right_Reduced(F) Input: - Tập PTH F Output: - Một phủ thu gọn phải G của F
(i) G F (ii) g:LRG,AR:G-{g}{LR-{A}}!G
Method
U := Attr(F);// Tập thuộc tính của F G := F; for each FD g:L R in F do X := R; for each attribute A in X do
if A in Closure(U,G-{g}{LR-{A}},L)
then delete A from R in G; endif;
endfor; if R = then delete L R from G; endif; endfor; return G;
Right_Reduced.
2.2.5 Thuật toán tìm phủ thu gọn của tập PTH F.
Định nghĩa: Cho hai tập PTH F và G trên tập thuộc tính U. G được gọi là phủ
thu gọn của F nếu G đồng thời là phủ thu gọn trái và thu gọn phải của F. [1,2]
Algorithm Reduced
28
Function: Tính phủ thu gọn của tập PTH Format: Reduced(F) Input: - Tập PTH F Output: - Một phủ thu gọn của F Method
return Right_Reduced(Left_Reduced(F));
end Reduced.
2.3. Các thuật toán tính bao đóng.
Định nghĩa: Cho tập PTH F trên tập thuộc tính U và một tập con các thuộc
tính X trong U. Bao đóng của tập thuộc tính X, ký hiệu X+ là tập thuộc tính
X+ = {A U | X AF+}
Thuật toán
Algorithm Closure Function: Tính bao đóng của tập thuộc tính. Format: Y = Closure(U,F,X) Input: - LĐQH p =(U,F) - Tập thuộc tính X U Output: - Y = X+ = { A U | XA F+ } Method Y := X; repeat Z := Y; for each FD L R in F do if L Y then Y := Y R; endif; endfor; until Y=Z; return Y; end Closure.
Độ phức tạp tính toán Giả sử mỗi lần lặp trong repeat ta chỉ thêm được 1 thuộc
tính. Khi đó repeat sẽ được lặp tối đa n lần. Mỗi lần lặp ta phải duyệt toàn bộ m
29
phụ thuộc hàm để thực hiện các thao tác trên các tập chứa tối đa n thuộc tính.
Vậy độ phức tạp tính toán sẽ là O(n2m). [1,2]
2.4. Các thuật toán khóa
Tư tưởng: Xuất phát từ một siêu khóa K tùy ý của LĐQH, duyệt lần lượt các
thuộc tính A của K, nếu bất biến (K{A})+ = U được bảo toàn thì loại A khỏi K.
Có thể thay kiểm tra (K{A})+ = U bằng kiểm tra A (K{A})+. [2]
Algorithm Key Function: Tìm một khóa của LĐQH
Format: Key(U,F) Input:
- Tập thuộc tính U - Tập thuộc PTH F
Output: - Khóa K U thỏa
(i) K+ = U (ii) AK: (K-{A})+ U Method K := U; for each attribute A in U do if A (K-{A})+ then K := K-{A} endif; endfor; return K;
end Key.
Độ phức tạp tính toán Trong thuật toán duyệt n thuộc tính, với mỗi thuộc tính
thực hiện phép lấy bao đóng với độ phức tạp n2m. Tổng hợp lại, độ phức tạp
tính toán của thuật toán là O(n3m). [1,2]
CHƯƠNG 3 – CÀI ĐẶT VÀ ỨNG DỤNG
30
Trong chương này tôi sẽ trình bày cài đặt và ứng dụng cho các thuật toán
theo hướng đối tượng cho thiết kế lớp tập hợp Set và lớp lược đồ quan hệ RSC
gồm:
3.1. Tiếp cận hướng đối tượng cho thiết kế
Theo tiếp cận hướng đối tượng ta có thể thiết kế và cài đặt một kiểu dữ liệu
mới. Luận văn sẽ tập trung thiết kế ba kiểu dữ liệu phục vụ cho các chương
trình xử lý các tập là:
Lớp tập hợp Set
Lớp lược đồ quan hệ RSC
3.2. Thiết kế lớp tập hợp Set
3.2.1 Các thuộc tính của lớp Set
const int __SETSIZE = 26;
typedef bitset<__SETSIZE> BS;
Ta định nghĩa kiểu dữ liệu BS như sau:
BS Data;
Trong lớp Set thuộc tính Data được định nghĩa là:
Như vậy, Data là trường dữ liệu chứa 0-25 bit
3.2.2 Các phương thức của lớp Set
Tạo tử (constructor)
inline Set() {
Data.reset();
}
Cú pháp
Ý nghĩa: Khởi tạo tập rỗng
Cú pháp
31
inline Set(const string s) {
for (int i = 0; i < s.length(); ++i)
if (IsAlpha(s[i]))
Data.set(Code(s[i]));
}
Data.reset();
Ý nghĩa: Khởi tạo Set nhận giá trị từ chuỗi s
Ví dụ: Set x(“ABC”);
Khi đó x chứa 2 phần từ A, B, C
inline Set(const Set &x) {
Data = x.Data;
}
Cú pháp
Ý nghĩa: Khởi tạo Set nhận giá trị của tập x cho trước
Set x(“ABC”);
Set y(x);
Ví dụ:
Khởi tạo x chứa 3 phần từ A, B, C
Set y(x) khởi tạo tập y nhận các giá trị của tập x là 3 phần từ A, B, C
inline void Reset() { Data.reset(); }
Cú pháp
Ý nghĩa: Reset một tập thành tập rỗng
Toán từ gán
Cú pháp
for (int i = 0; i < s.length(); ++i)
if (IsAlpha(s[i]))
Data.set(Code(s[i]));
32
inline void operator =(const string s) { Data.reset(); }
Ý nghĩa : Gán một chuỗi từ tập x
Lấy giá trị của tập hợp
return (Data[i]) ? ToAlpha(i) : NULL;
if (Data[i]) } return NULL;
inline char operator[](int i) const {
if (i >= 0 && i < __SETSIZE) { }
Cú pháp
Ý nghĩa: Lấy phần từ thứ i cuả tập hợp.
Kiểm tra tập hợp có phải là tập rỗng hay không
inline bool Empty() const {return Data.none();}
Cú pháp
Ý nghĩa:
Kiểm tra một phần tử có thuộc tập hợp hay không
return Data[Code(e)];
if (IsAlpha(e)) return 0;
inline bool IsIn(char e) { }
Cú pháp
Lực lượng của tập hợp
Cú pháp
inline int Card() const {return Data.count();
Ý nghĩa: trả về số của tập hợp
Thêm phần tử vào tập hợp
Cú pháp
33
} Ý nghĩa : Thêm phần từ e vào tập x
inline void Ins(char e) { if (IsAlpha(e)) Data.set(Code(e));
Xóa phần từ
inline void Del(char e) {
if (IsAlpha(e)) Data.reset(Code(e));
} Ý nghĩa : Xóa phần tử e từ tập hợp
Cú pháp
Thêm phần tử
inline void Add(char e) {Ins(e);
Cú pháp
Ý nghĩa: Thêm phần tử e vào tập hợp
3.2.3 Các phép toán tập hợp
Hợp của hai tập hợp
Set operator +(const Set &y) const {
Set z(*this); z.Data |= y.Data; return z;
}
inline void operator +=(const Set &y) { *this = *this + y; }
Ý nghĩa: Trả về hợp của 2 tập hợp
Cú pháp
Giao của hai tập hợp
Set operator *(const Set &y) const {
Set z(*this); z.Data &= y.Data;
return z;
}
inline void operator *=(const Set &y) { *this = *this * y;
Cú pháp
}
34
Ý nghĩa: Trả về giao của 2 tập hợp
Hiệu của hai tập hợp
Set operator -(const Set &y) const {
z.Data[i] = 1;
Set z;
for (int i = 0; i < __SETSIZE; ++i) if (Data[i] && (!y.Data[i])) return z;
}
inline void operator -=(const Set &y) {
*this = *this - y;
}
Cú pháp
Ý nghĩa: Trả về hiệu của 2 tập hợp
So sánh hai phần tử
So sánh bằng
inline bool operator ==(const Set & y) const {
return Data == y.Data;
} Ý nghĩa: So sánh hai tập hợp có bằng nhau hay không
Cú pháp
So sánh khác
inline bool operator !=(const Set & y) const {
return Data != y.Data;
} Ý nghĩa: So sánh hai tập hợp có khác nhau hay không
Cú pháp
So sánh nhỏ hơn hoặc bằng
inline friend bool operator <=(const Set & x, const Set & y){ for (int i = 0; i < __SETSIZE; ++i)
if (x.Data[i] && (!y.Data[i]))
return false;
return true; }
Cú pháp
35
Ý nghĩa: So sánh hai tập hợp có nhỏ hơn hoặc bằng nhau không.
So sánh lớn hơn hoặc bằng
inline friend bool operator >=(const Set & x, const Set & y){
return y <= x;
}
Cú pháp
Ý nghĩa: So sánh hai tập hợp có lớn hơn hoặc bằng nhau không.
So sánh nhỏ hơn
friend bool operator <(const Set & x, const Set & y) {
return((x <= y) && (x != y));
} Ý nghĩa: So sánh hai tập hợp có nhỏ hơn không
Cú pháp
So sánh lớn hơn
inline friend bool operator >(const Set & x, const Set & y) {
return y < x;
} Ý nghĩa: So sánh hai tập hợp có lớn hơn không
Cú pháp
Hiển thị
friend ostream & operator <<(ostream & os, const Set & s) {
}
os << "{}"; return os;
os << ToAlpha(i);
if (s.Empty()) { for (int i = 0; i < __SETSIZE; ++i) { if (s.Data[i]) } return os;
}
Cú pháp
Ý nghĩa: Hiển thị các phần tử ra màn hình
inline void Print(string msg = "") {
Cú pháp
return;
cout << "{}"; }
cout << ToAlpha(i);
36
cout << msg; if (Empty()) { for (int i = 0; i < __SETSIZE; ++i) { if (Data[i]) } } } Ý nghĩa: Hiển thị các phần tử ra màn hình và kèm theo thông báo msg
Ví dụ: Chương trình Demoset.cpp thực hiện các thao tác như sau:
1. Khai báo tập x, y
2. So sánh tập x có lớn hơn hoặc bằng tập y hay không
3. Hiển thị ra màn hình tập x, y
Như vậy ta thu được
Demoset.cpp
*************************************************/
#include
BS Data;
protected: public: inline Set() { Data.reset(); }
for (int i = 0; i < s.length(); ++i)
if (IsAlpha(s[i]))
Data.set(Code(s[i]));
inline Set(const string s) { Data.reset(); } inline Set(const Set &x) { Data = x.Data; }
/******************************************
Data.set(Code(s[i]));
if (IsAlpha(s[i]))
for (int i = 0; i < s.length(); ++i)
return (Data[i]) ? ToAlpha(i) :
if (Data[i]) } return NULL; // (char)0;
return Data[Code(e)];
inline bool IsIn(char e) { if (IsAlpha(e)) return 0;
inline int Card() const {return Data.count();}
z.Data |= y.Data; return z;
inline void Reset() { Data.reset(); } inline void operator =(const Set & y) { Data = y.Data; } inline void operator =(const string s) { Data.reset(); } inline char operator[](int i) const { if (i >= 0 && i < __SETSIZE) { NULL; } inline bool Empty() const {return Data.none();} } inline bool Has(char e) {return IsIn(e);} inline void Ins(char e) { if (IsAlpha(e)) Data.set(Code(e)); } inline void Del(char e) { if (IsAlpha(e)) Data.reset(Code(e)); } inline void Add(char e) {Ins(e);} Set operator +(const Set &y) const { Set z(*this); }
37
inline void operator +=(const Set &y) {
}
z.Data &= y.Data; return z;
inline void operator *=(const Set &y) {
}
z.Data[i] = 1;
for (int i = 0; i < __SETSIZE; ++i) if (Data[i] && (!y.Data[i])) return z;
inline void operator -=(const Set &y) {
}
return Data == y.Data;
inline bool operator ==(const Set & y) const { }
return Data != y.Data;
inline bool operator !=(const Set & y) const { }
inline friend bool operator <=(const Set & x, const
return false;
}
inline friend bool operator >=(const Set & x, const
return y <= x;
friend bool operator <(const Set & x, const Set &
*this = *this + y; Set operator *(const Set &y) const { Set z(*this); } *this = *this * y; Set operator -(const Set &y) const { Set z; } *this = *this - y; Set & y) { for (int i = 0; i < __SETSIZE; ++i) if (x.Data[i] && (!y.Data[i])) return true; Set & y) { } y) { return((x <= y) && (x != y)); }
38
inline friend bool operator >(const Set & x, const
return y < x;
}
if (s.Empty()) {
os << ToAlpha(i);
return;
cout << "{}"; }
cout << ToAlpha(i);
Set & y) { } friend ostream & operator <<(ostream & os, const Set & s) { os << "{}"; return os; for (int i = 0; i < __SETSIZE; ++i) { if (s.Data[i]) } return os; } inline void Print(string msg = "") { cout << msg; if (Empty()) { for (int i = 0; i < __SETSIZE; ++i) { if (Data[i]) } } };
void TestSet() {
cout << x[i];
if (y[i] != NULL) cout << y[i];
Set x, y; x = "AB"; y = "BDE"; cout << "\n x = " << x; cout << "\n y = " << y; cout << "\n x >= y ? " << (x >= y); cout << endl; for (int i = 0; i < 26; ++i) { } cout << endl; for (int i = 0; i < 26; ++i) { } cout << endl; for (int i = 0; i < 26; ++i) { }
cout << z[i];
}
39
40
TestSet(); cout << "\n T H E E N D .";
return 0;
Main() {
} Kết quả thực hiện
Màn hình
3.3 Thiết kế lớp lược đồ quan hệ RSC
3.3.1 Các thuôc tính của lớp lược đồ quan hệ RSC
Set Attr;
int FDNum;
FD * F;
int Cap;
Set Key;
Cú pháp
Ý nghĩa: Khai báo các thuộc tính, phụ thuộc hàm
3.3.2 Các phương thức của lớp lược đồ quan hề RSC
Tạo tử (constructor)
inline RSC() {Reset();}
inline RSC(const RSC &r) {
Reset(); Copy(r);
Cú pháp
} Hủy tử (destructor)
41
if (F != NULL) { delete [] F; F = NULL;
}
~RSC() { }
Cú pháp
Ý nghĩa: Xóa và thu hồi vùng nhớ đã cấp phát cho lớp lược đồ quan hề RSC
Cấp phát vùng chứa tên phần tử của lớp lược đồ quan hệ RSC
inline void Renew()
Cú pháp
Ý nghĩa: Cấp phát vùng nhớ đủ chứa size phần tử cho tập nền. Vùng nhớ này
để lưu trữ danh sách (tên) các phần tử của tập nền.
Trả về vùng chứa phần tử của lớp lược đồ quan hệ RSC
void Reset() { FDNum = 0; Cap = 0; F = NULL; Attr.Reset(); Key.Reset(); } Ý nghĩa: Gán độ thuộc 0 cho mọi phần tử của lớp lược đồ quan hệ RSC
Cú pháp
Toán tử gán
void Copy(const RSC & r) {
F = NULL;
for(int i = 0; i < FDNum; ++i)
F[i] = r.F[i];
Attr = r.Attr; FDNum = r.FDNum; // so PTH Cap = r.Cap; // Capacity Key = r.Key;
delete [] F; if (r.F == NULL) else {
F = new FD[Cap]; }
Cú pháp
42
}
Mở rộng vùng chứa lớp lược đồ quan hệ RSC
g[i] = F[i];
int newCap = Cap + __UNIT; FD *g = new FD[newCap]; for(int i = 0; i < FDNum; ++i) Cap = newCap; delete [] F; F = g;
void Extend() { } Ý nghĩa: Mở rộng vùng chứa lớp lược đồ quan hệ RSC
Cú pháp
Chèn mới
Cap = __UNIT; F = new FD[Cap]; F[0].Put(ls,rs); FDNum = 1; Attr = F[0].GetLR(); return;
if (F == NULL) { } if (FDNum == Cap) Extend(); F[FDNum].Put(ls,rs); ++FDNum; Attr += (ls + rs);
void Ins(const Set & ls, const Set & rs) { } void Ins(string ls, string rs) {Ins(Set(ls), Set(rs));}
Cú pháp
Set Closure(const Set & x, int k = -1) { bitset<1000> mark; // danh dau cac FD da dung Set y = x; int used = 0; while(true) {
used = 0; for (int i = 0; i < FDNum; ++i) {
if (i == k) continue; if (mark[i] == 0) { if (F[i].GetLS() <= y) {
Cú pháp
y += F[i].GetRS(); mark[i] = 1; ++used;
}
} } if (used == 0) break;
43
} return y; } Ý nghĩa: Tạo phụ thuộc hàm của lược đồ quan hệ RSC
k.Ins(c);
k.Del(c); if (!(Closure(k).Has(c))) }
Set FindKey() { Set k = Attr; for (char c = 'A'; c <= 'Z'; ++c) { if (k.Has(c)) { } return k; } inline Set SetKey() { Key = FindKey(); return Key; } inline void NewKey(const Set &k) { Key = k; } inline void NewKey(const string s) { Key = Set(s); } Ý nghĩa: Tìm khóa cho lược đồ quan hệ RSC
Cú pháp
Ví dụ:
Cho lược đồ quan hệ VẬN CHUYỂN (số_vận_đơn, kho_hàng, nơi_đến,
khoảng_cách)
Ta mã hóa đặt: số_vận_đơn = A, kho_hàng = B, nơi_đến = C, khoảng_cách =
D. Số thuộc tính U=ABCD
44
Với các tập phụ thuộc hàm: số_vận_chuyển xác định kho_hàng, nơi_đến,
khoảng_cách. Kho_hàng, nơi_đến xác định khoảng_cách.
F={A BCD, BC D}
Mở file”K.txt” rồi ghi vào file, ta thực hiện tìm khóa K của lược đồ quan hệ VẬN
CHUYỂN. Cuối cùng ta ghi vào output tổng số lượng khóa của lược đồ quan hệ
VẬN CHUYỂN.
Muốn tìm khóa của LĐQH:
Cho LĐQH p = (U,F). Tập thuộc tính K U được gọi là khoá của LĐ p nếu
(i) K + = U
(ii) A K: (K {A})+ U
Hai điều kiện trên tương đương với
(i') K U
(ii') A K: (K {A}) ! U
Nếu K thoả điều kiện (i) thì K được gọi là một siêu khoá.
Thuộc tính A U được gọi là thuộc tính khoá (nguyên thuỷ hoặc cơ sở)
nếu A có trong một khoá nào đấy. A được gọi là thuộc tính không khoá (phi
nguyên thuỷ hoặc thứ cấp) nếu A không có trong bất kỳ khoá nào. Cho LĐQH
(U,F), ta kí hiệu UK là tập các thuộc tính khóa và Uo là tập các thuộc tính không
khóa.
*******************************************
Chương trình
#include
protected:
*******************************************
Set Attr; // Attribute Set int FDNum; // number of functional dependencies FD * F; // functional dependencies int Cap; // Capacity Set Key; void Reset() { FDNum = 0; Cap = 0; F = NULL; Attr.Reset(); Key.Reset(); }
k.Del(c); if (!(Closure(k).Has(c)))
k.Ins(c);
if (k.Has(c)) { }
Set k = Attr; for (char c = 'A'; c <= 'Z'; ++c) { } return k;
Key = FindKey(); return Key;
Key = k;
}
Key = Set(s);
}
if (!(x <= Attr)) return false; if (Key <= x) return true; return Attr <= Closure(x);
}
return IsSuperkey(Set(s));
}
45
Set FindKey() { } inline Set SetKey() { } inline void NewKey(const Set &k) { inline void NewKey(const string s) { inline bool IsSuperkey(const Set &x) { inline bool IsSuperkey(const string s) { bool IsKey(const Set &x) {
k.Del(c); if (Closure(k).IsIn(c)) return false; k.Ins(c);
if (k.IsIn(c)) { }
if (!IsSuperkey(x)) return false; Set k = x; for (char c ='A'; c <= 'Z'; ++c) { } return true;
}
return IsKey(Set(s));
}
}
TestRSC(); cout << "\n T H E E N D ."; return 0;
46
inline bool IsKey(const string s) { void TestRSC() { RSC r; r.Read("K.txt"); r.Show("\n r: "); cout << "\n Key : " << r.GetKey(); main() { }
Kết quả ra màn hình
47
Nội dung file “K.txt”
Ví dụ: Chương trình DemoSC.cpp thực hiện các thao tác như sau: Cho một lược
đồ quan hê ĐƠN HÀNG (số_đơn, mã_KH, tên_KH, địa_chỉ_KH, ngày_đặt,
48
mã_hàng, tên_hàng, đơn_vị, mô_tả, số_lượng). Ta mã hóa đặt: số_đơn = A,
mã_KH = B, tên_KH = C, địa_chỉ_KH =D, ngày_đặt = E, mã_hàng = F,
tên_hàng = G, đơn_vị =H, mô_tả =I, số_lượng = J
Số thuộc tính U=ABCDEFGHIJ
Tập phụ thuộc hàm xác định: mã_KH xác định tên_KH, địa_chỉ_KH; mã_hàng
xác định tên_hàng, đơn_vị, mô_tả; số_đơn xác định mã_KH, ngày_đặt,
mã_hàng. Ta viết tắt như sau F={B CD; F GHI; AF J; A BEF}. Mở
file “K.txt” rồi ghi vào file, ta hiển thị số tập thuộc tính, tìm khóa K của lược đồ
quan hệ ĐƠN HÀNG. Tìm tập phụ thuộc hàm của AB và tập phụ thuộc F, kiểm
tra E có phải là khóa của lược đồ quan hệ không. Cuối cùng ta ghi vào output
file của lược đồ quan hệ ĐƠN HÀNG.
Chương trình
DemoSC.cpp
*************************************************/
#include
Set Attr; // Attribute Set int FDNum; // number of functional dependencies FD * F; // functional dependencies int Cap; // Capacity Set Key; void Reset() { FDNum = 0; Cap = 0; F = NULL; Attr.Reset(); Key.Reset(); }
protected:
/*******************************************
Copy(r);
inline RSC() {Reset();} inline RSC(const RSC &r) { Reset(); }
delete [] F; F = NULL;
if (F != NULL) { }
~RSC() { }
delete [] F;
Reset(); if (F != NULL) F = NULL;
public: inline void Renew() { } // Renew private:
F = NULL;
F = new FD[Cap]; for(int i = 0; i < FDNum; ++i)
F[i] = r.F[i];
Attr = r.Attr; // Tap thuoc tinh
FDNum = r.FDNum; // so PTH Cap = r.Cap; // Capacity Key = r.Key; delete [] F; if (r.F == NULL) else { }
inline int GetFDNum() const {return FDNum;} inline Set GetKey() const {return Key;}
49
int newCap = Cap + __UNIT; FD *g = new FD[newCap];
void Extend() {
void Copy(const RSC & r) { } public: inline void operator =(const RSC & r) {Copy(r);}
g[i] = F[i];
for(int i = 0; i < FDNum; ++i) Cap = newCap; delete [] F; F = g;
if (F == NULL) {
Cap = __UNIT; F = new FD[Cap]; F[0].Put(ls,rs); FDNum = 1; Attr = F[0].GetLR(); return;
} if (FDNum == Cap) Extend(); F[FDNum].Put(ls,rs); ++FDNum; Attr += (ls + rs);
} void Ins(const Set & ls, const Set & rs) { } void Ins(string ls, string rs) {Ins(Set(ls),
if (F[k].GetLS() == F[i].GetLS()) { F[k].AddRS(F[i].GetRS()); --j; break;
if (F[i].GetRS().Empty()) continue; ++j; F[j] = F[i]; for (int k = 0; k < j; ++k) { } }
int j = -1; int k; for (int i = 0; i < FDNum; ++i) { } FDNum = j+1; Attr.Reset(); for (int i = 0; i < FDNum; ++i) { }
Attr += F[i].GetLR();
void Norm() { }
Set Closure(const Set & x, int k = -1) {
50
Set(rs));}
y += F[i].GetRS(); mark[i] = 1; ++used;
if (F[i].GetLS() <= y) { }
if (i == k) continue; if (mark[i] == 0) { }
used = 0; for (int i = 0; i < FDNum; ++i) { } if (used == 0) break;
bitset<1000> mark; // danh dau cac FD da dung Set y = x; int used = 0; while(true) { } return y;
return Closure(Set(s),k);
k.Del(c); if (!(Closure(k).Has(c)))
k.Ins(c);
if (k.Has(c)) { }
Set k = Attr; for (char c = 'A'; c <= 'Z'; ++c) { } return k;
Key = k;
Key = Set(s);
} inline Set Closure(const string s, int k = -1) { } Set FindKey() { } inline Set SetKey() { Key = FindKey(); return Key; } inline void NewKey(const Set &k) { } inline void NewKey(const string s) { } inline bool IsSuperkey(const Set &x) {
51
if (!(x <= Attr)) return false; if (Key <= x) return true; return Attr <= Closure(x);
} inline bool IsSuperkey(const string s) {
return IsSuperkey(Set(s));
k.Del(c); if (Closure(k).IsIn(c)) return false; k.Ins(c);
if (k.IsIn(c)) { }
if (!IsSuperkey(x)) return false; Set k = x; for (char c ='A'; c <= 'Z'; ++c) { } return true;
return IsKey(Set(s));
return (Closure(g.GetLS(),k) >= g.GetRS());
return Derive(FD(ls,rs),k);
F[i] = F[FDNum-1];
if (FDNum-1 > i) { } --FDNum;
for(int i = FDNum-1; i >= 0; --i) { }
if (Derive(F[i],i)) { }
} bool IsKey(const Set &x) { } inline bool IsKey(const string s) { } bool Derive(const FD & g, int k = -1) { } bool Derive(string ls, string rs, int k = -1) { } // Derive void NonRedundant() { } void Read(const char * fn) {
ifstream f(fn); if (f.fail()) {
52
cerr << "\n Unable open in file " << fn; return;
rs += s[i];
if (IsAlpha(s[i]))
getline(f,s); cout << "\n " << s; if (s[0] == '.') break; // Left Side ls = ""; for (i = 0; s[i] != '-'; ++i) { if (IsAlpha(s[i])) ls += s[i]; } rs = ""; for (i = i+1; i < s.length(); ++i) { } Ins(ls,rs); // New FD ls -> rs
} Reset(); cout << "\n Reading ... "; string s; string ls, rs; int i; while(true) { } f.close(); Norm(); Show("\n Read: "); NonRedundant(); SetKey();
if (!IsSuperkey(F[i].GetLS())) return false;
for (int i = 0; i < FDNum; ++i) { } return true;
} inline bool IsBCNF() { }
void Print(string msg = "") {
cout << "\n " << i << ". "; F[i].Print();
}
53
cout << msg; Attr.Print("\n Attribute Set: "); Key.Print("\n Key: "); cout << "\n Functional Dependencies: "; for (int i = 0; i < FDNum; ++i) { }
os << s.Attr;
os << "\n Attribute Set: ";
os << "\n " << i << ". " << s.F[i];
return os;
cout << msg; cout << "\n Cap: " << Cap; cout << "\n Number of FDs: " << FDNum; Print();
void Show(string msg = "") { }
void TestRSC() { RSC r; r.Read("K.txt"); r.Show("\n r: "); cout << "\n Key : " << r.GetKey(); cout << "\n AB? " << r.Closure("AB");
cout << "\n E is a key? " << r.IsKey("ED");
}
TestRSC(); cout << "\n T H E E N D ."; return 0;
54
friend ostream & operator <<(ostream & os, const RSC & s) { os << "\n Functional Dependencies: "; for (int i = 0; i < s.FDNum; ++i) } }; cout << "\n F? " << r.Closure("F"); main() { }
55
Kết quả thực hiện
Màn hình
56
Nội dung file “K.txt”
Ví dụ: Chương trình Demo.cpp thực hiện các thao tác như sau: Cho một lược đồ
quan hê PHIEUMUONSACH (Maphieu, tenDG, Ngaymuon, Ngaytra, Masach,
Tensach). Ta mã hóa đặt: maphieu = A, tenDG = B, ngaymuon = C, ngaytra =D,
masach = E, tensach = F. Số thuộc tính U=ABCDEF
Tập phụ thuộc hàm xác định: maphieu xác định tenDG, ngaymuon, ngaytra;
masach xác định tensach. Ta viết tắt như sau F={A BCD; E F). Mở file
“K.txt” rồi ghi vào file, ta hiển thị số tập thuộc tính, tìm khóa K của lược đồ
quan hệ PHIEUMUONSACH . Tìm khóa của lược đồ quan hệ, tìm tập phụ thuộc
hàm của A và kiểm tra D có phải là khóa của lược đồ quan hệ không. Cuối cùng
ta ghi vào output file của lược đồ quan hệ PHIEUMUONSACH.
57
Chương trình
Demo.cpp
Set Attr; // Attribute Set int FDNum; // number of functional dependencies FD * F; // functional dependencies int Cap; // Capacity Set Key; void Reset() { FDNum = 0; Cap = 0; F = NULL; Attr.Reset(); Key.Reset(); }
Copy(r);
inline RSC() {Reset();} inline RSC(const RSC &r) { Reset(); }
if (F != NULL) { }
delete [] F; F = NULL;
~RSC() { }
*************************************************/
#include
protected: public: inline void Renew() {
Reset(); if (F != NULL)
delete [] F;
/*******************************************
F = NULL;
} // Renew private:
F = NULL;
F[i] = r.F[i];
F = new FD[Cap]; for(int i = 0; i < FDNum; ++i)
FDNum = r.FDNum; // so PTH Cap = r.Cap; // Capacity Key = r.Key; delete [] F; if (r.F == NULL) else { }
Attr = r.Attr; // Tap thuoc tinh
inline int GetFDNum() const {return FDNum;} inline Set GetKey() const {return Key;}
g[i] = F[i];
int newCap = Cap + __UNIT; FD *g = new FD[newCap]; for(int i = 0; i < FDNum; ++i) Cap = newCap; delete [] F; F = g;
Cap = __UNIT; F = new FD[Cap]; F[0].Put(ls,rs); FDNum = 1; Attr = F[0].GetLR(); return;
if (F == NULL) {
58
void Extend() { } void Ins(const Set & ls, const Set & rs) {
} if (FDNum == Cap) Extend(); F[FDNum].Put(ls,rs);
void Copy(const RSC & r) { } public: inline void operator =(const RSC & r) {Copy(r);}
++FDNum; Attr += (ls + rs);
} void Ins(string ls, string rs) {Ins(Set(ls),
if (F[k].GetLS() == F[i].GetLS()) { F[k].AddRS(F[i].GetRS()); --j; break;
if (F[i].GetRS().Empty()) continue; ++j; F[j] = F[i]; for (int k = 0; k < j; ++k) { } }
int j = -1; int k; for (int i = 0; i < FDNum; ++i) { } FDNum = j+1; Attr.Reset(); for (int i = 0; i < FDNum; ++i) { }
Attr += F[i].GetLR();
void Norm() { }
y += F[i].GetRS(); mark[i] = 1; ++used;
if (F[i].GetLS() <= y) { }
if (i == k) continue; if (mark[i] == 0) { }
used = 0; for (int i = 0; i < FDNum; ++i) { } if (used == 0) break;
bitset<1000> mark; // danh dau cac FD da dung Set y = x; int used = 0; while(true) { } return y;
Set Closure(const Set & x, int k = -1) { } inline Set Closure(const string s, int k = -1) {
59
Set(rs));}
return Closure(Set(s),k);
k.Ins(c);
k.Del(c); if (!(Closure(k).Has(c)))
if (k.Has(c)) { }
Set k = Attr; for (char c = 'A'; c <= 'Z'; ++c) { } return k;
Key = k;
Key = Set(s);
if (!(x <= Attr)) return false; if (Key <= x) return true; return Attr <= Closure(x);
} Set FindKey() { } inline Set SetKey() { Key = FindKey(); return Key; } inline void NewKey(const Set &k) { } inline void NewKey(const string s) { } inline bool IsSuperkey(const Set &x) { } inline bool IsSuperkey(const string s) {
return IsSuperkey(Set(s));
k.Del(c); if (Closure(k).IsIn(c)) return false; k.Ins(c);
} bool IsKey(const Set &x) {
if (!IsSuperkey(x)) return false; Set k = x; for (char c ='A'; c <= 'Z'; ++c) {
if (k.IsIn(c)) { }
60
} return true;
return IsKey(Set(s));
return (Closure(g.GetLS(),k) >= g.GetRS());
return Derive(FD(ls,rs),k);
F[i] = F[FDNum-1];
if (FDNum-1 > i) { } --FDNum;
if (Derive(F[i],i)) { }
for(int i = FDNum-1; i >= 0; --i) { }
cerr << "\n Unable open in file " << fn; return;
} inline bool IsKey(const string s) { } bool Derive(const FD & g, int k = -1) { } bool Derive(string ls, string rs, int k = -1) { } // Derive void NonRedundant() { } void Read(const char * fn) {
ifstream f(fn); if (f.fail()) { } Reset(); cout << "\n Reading ... "; string s; string ls, rs; int i; while(true) {
getline(f,s); cout << "\n " << s; if (s[0] == '.') break; // Left Side ls = ""; for (i = 0; s[i] != '-'; ++i) { if (IsAlpha(s[i])) ls += s[i]; } rs = ""; for (i = i+1; i < s.length(); ++i) {
if (IsAlpha(s[i]))
61
rs += s[i];
} Ins(ls,rs); // New FD ls -> rs
} f.close(); Norm(); Show("\n Read: "); NonRedundant(); SetKey();
if (!IsSuperkey(F[i].GetLS())) return false;
for (int i = 0; i < FDNum; ++i) { } return true;
} inline bool IsBCNF() { }
void Print(string msg = "") {
cout << "\n " << i << ". "; F[i].Print();
}
os << "\n Attribute Set: ";
os << s.Attr;
os << "\n " << i << ". " << s.F[i];
return os;
cout << msg; cout << "\n Cap: " << Cap; cout << "\n Number of FDs: " << FDNum; Print();
void Show(string msg = "") { }
62
void TestRSC() {
cout << msg; Attr.Print("\n Attribute Set: "); Key.Print("\n Key: "); cout << "\n Functional Dependencies: "; for (int i = 0; i < FDNum; ++i) { } friend ostream & operator <<(ostream & os, const RSC & s) { os << "\n Functional Dependencies: "; for (int i = 0; i < s.FDNum; ++i) } };
RSC r; r.Read("K.txt"); r.Show("\n r: "); cout << "\n Key : " << r.GetKey(); cout << "\n A? " << r.Closure("A");
}
TestRSC(); cout << "\n T H E E N D ."; return 0;
63
cout << "\n D is a key? " << r.IsKey("ED"); main() { }
Kết quả thực hiện
Màn hình
64
Nội dung file “K.txt”
65
KẾT LUẬN
Luận văn đã thu được những kết quả chính sau đây:
Cài đặt các lớp đối tượng quản lý tập hợp, thuộc tính, phụ thuộc hàm,
khóa, dạng chuẩn 3NF.
Thử nghiệm các lược đồ quan hệ.
Việc nghiên cứu đề tài có thể đóng góp thêm một vài chức năng quản lý
ngữ nghĩa dữ liệu thông qua các dạng chuẩn.
Luận văn thiết kế và cài đặt một hệ thống với các chức năng nhập xuất,
lưu trữ, tính bao đóng, khóa của các lược đồ quan hệ và các thuật toán
chuẩn hóa 3NF. Hệ thống có thể được sử dụng để khảo sát và kiểm định
các dạng chuẩn và các quy trình chuẩn hóa lược đồ quan hệ.
Hướng phát triển
Theo gợi ý của các chuyên gia nghiên cứu về cơ sở dữ liệu, đề tài luận văn
có thể tiếp tục phát triển các thuật toán thiết kế cơ sở dữ liệu dạng phi chuẩn
theo tiếp cận cơ sở dữ liệu hướng đối tượng, trong đó các thuộc tính có thể
chứa các thuật tính khác.
66
TÀI LIỆU THAM KHẢO
[1] Nguyễn Xuân Huy (2003), Bài tập Cơ sở dữ liệu, NXB Thống Kê.
[2] Nguyễn Xuân Huy (2006), Các phụ thuộc logic trong cơ sở dữ liệu,
[3] Vũ Đức Thái (2016), Thiết kế cơ sở dữ liệu, NXB Đại học Thái
Viện Khoa học và Công nghệ Việt Nam.
[4] Vũ Đức Thi (1997), Cơ sở dữ liệu: Kiến thức và thực hành, NXB Thống
Nguyên.
[5] Lê Tiến Vương (2000), Nhập môn cơ sở dữ liệu quan hệ, NXB Thống
Kê.
[6] Date C. J., Nhập môn các hệ cơ sở dữ liệu, Những người dịch: Hồ Thuần, Nguyễn Quang Vinh, Nguyễn Xuân Huy, NXB Thống Kê, Hà Nội, Tập I (1985), Tập II (1986).
[7] Jaume Baixeries, Mehdi Kaytoue, Amedeo Napoli
Kê.
[8] Maier D. (1983), The Theory of Relational Database, Computer
(2014), Characterization of Database Dependencies with FCA and Pattern Structures, Procc. Third International Conference, Analysis of Images, Social Networks and Texts (AIST 2014), Yekaterinburg, Russia. Springer, 436, pp.3 - 14, 2014, Communications in Computer and Information Science.
[9] Ullman, J. (1982), Principles of Data-base and Knowledge-base Systems, Second Edition, Computer Science Press, Potomac. (Có bản dịch tiếng Việt của Trần Đức Quang.)
Science Press, Rockville.