6. Cấu trúc của luận văn
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
Ta định nghĩa kiểu dữ liệu BS như sau:
const int __SETSIZE = 26; typedef bitset<__SETSIZE> BS;
Trong lớp Set thuộc tính Data được định nghĩa là:
BS Data;
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)
Cú pháp
inline Set() { Data.reset();
}
Ý nghĩa: Khởi tạo tập rỗng
inline Set(const string s) {
Data.reset();
for (int i = 0; i < s.length(); ++i)
if (IsAlpha(s[i]))
Data.set(Code(s[i]));
}
Ý 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
Cú pháp
inline Set(const Set &x) {
Data = x.Data; }
Ý nghĩa: Khởi tạo Set nhận giá trị của tập x cho trước Ví dụ:
Set x(“ABC”);
Set y(x);
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 Cú pháp
inline void Reset() {
Data.reset();
}
Ý nghĩa: Reset một tập thành tập rỗng
Toán từ gán
inline void operator =(const string s) { Data.reset();
for (int i = 0; i < s.length(); ++i) if (IsAlpha(s[i]))
Data.set(Code(s[i])); }
Ý nghĩa : Gán một chuỗi từ tập x
Lấy giá trị của tập hợp
Cú pháp
inline char operator[](int i) const {
if (i >= 0 && i < __SETSIZE) {
if (Data[i])
return (Data[i]) ? ToAlpha(i) : NULL; }
return NULL; }
Ý 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
Cú pháp
inline bool Empty() const {return Data.none();}
Ý nghĩa:
Kiểm tra một phần tử có thuộc tập hợp hay không
Cú pháp
inline bool IsIn(char e) {
if (IsAlpha(e)) return Data[Code(e)]; return 0; } 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
inline void Ins(char e) { if (IsAlpha(e))
Data.set(Code(e)); }
Ý nghĩa : Thêm phần từ e vào tập x
Xóa phần từ
Cú pháp
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 Thêm phần tử Cú pháp
inline void Add(char e) {Ins(e);
Ý 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
Cú phá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
Giao của hai tập hợp
Cú phá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ề giao của 2 tập hợp
Hiệu củahai tập hợp
Cú pháp
Set operator -(const Set &y) const { Set z;
for (int i = 0; i < __SETSIZE; ++i) if (Data[i] && (!y.Data[i]))
z.Data[i] = 1; return z;
}
inline void operator -=(const Set &y) {
*this = *this - y;
}
Ý 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
Cú pháp
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
So sánh khác
Cú pháp
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
So sánh nhỏ hơn hoặc bằng
Cú pháp
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; }
Ý 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
Cú pháp
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 hoặc bằng nhau không.
So sánh nhỏ hơn
Cú pháp
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
So sánh lớn hơn
Cú pháp
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
Hiển thị
Cú pháp
friend ostream & operator <<(ostream & os, const Set & s) { if (s.Empty()) {
os << "{}"; return os; }
for (int i = 0; i < __SETSIZE; ++i) { if (s.Data[i]) os << ToAlpha(i); } return os; } Ý nghĩa: Hiển thị các phần tử ra màn hình Cú pháp
cout << msg; if (Empty()) {
cout << "{}"; return; }
for (int i = 0; i < __SETSIZE; ++i) { if (Data[i])
cout << ToAlpha(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 <iostream> #include <fstream> #include <bitset> using namespace std;
const int __SETSIZE = 26; const int __UNIT = 16;
typedef bitset<__SETSIZE> BS; class Set { protected: BS Data; public: inline Set() { Data.reset(); }
inline Set(const string s) { Data.reset();
for (int i = 0; i < s.length(); ++i) if (IsAlpha(s[i]))
Data.set(Code(s[i])); }
inline Set(const Set &x) { Data = x.Data;
}
inline void Reset() {
Data.reset();
}
inline void operator =(const Set & y) { Data = y.Data;
}
inline void operator =(const string s) { Data.reset();
for (int i = 0; i < s.length(); ++i) if (IsAlpha(s[i]))
Data.set(Code(s[i])); }
inline char operator[](int i) const { if (i >= 0 && i < __SETSIZE) {
if (Data[i])
return (Data[i]) ? ToAlpha(i) :
NULL;
}
return NULL; // (char)0; }
inline bool Empty() const {return Data.none();}
inline bool IsIn(char e) {
if (IsAlpha(e))
return Data[Code(e)];
return 0;
}
inline bool Has(char e) {return IsIn(e);}
inline int Card() const {return Data.count();}
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);
z.Data |= y.Data; return z;
inline void operator +=(const Set &y) {
*this = *this + y;
}
Set operator *(const Set &y) const { Set z(*this);
z.Data &= y.Data; return z;
}
inline void operator *=(const Set &y) {
*this = *this * y;
}
Set operator -(const Set &y) const { Set z;
for (int i = 0; i < __SETSIZE; ++i) if (Data[i] && (!y.Data[i]))
z.Data[i] = 1; return z;
}
inline void operator -=(const Set &y) {
*this = *this - y;
}
inline bool operator ==(const Set & y) const {
return Data == y.Data;
}
inline bool operator !=(const Set & y) const {
return Data != y.Data;
}
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;
}
inline friend bool operator >=(const Set & x, const
Set & y) {
return y <= x;
}
friend bool operator <(const Set & x, const Set &
y) {
return((x <= y) && (x != y)); }
inline friend bool operator >(const Set & x, const Set & y) {
return y < x;
}
friend ostream & operator <<(ostream & os, const Set & s) {
if (s.Empty()) {
os << "{}"; return os; }
for (int i = 0; i < __SETSIZE; ++i) { if (s.Data[i]) os << ToAlpha(i); } return os; }
inline void Print(string msg = "") { cout << msg;
if (Empty()) {
cout << "{}"; return; }
for (int i = 0; i < __SETSIZE; ++i) { if (Data[i]) cout << ToAlpha(i); } } }; void TestSet() { 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 << x[i];
}
cout << endl;
for (int i = 0; i < 26; ++i) {
if (y[i] != NULL) cout << y[i]; }
cout << endl;
for (int i = 0; i < 26; ++i) { cout << z[i];
} }
Main() { TestSet(); cout << "\n T H E E N D ."; return 0; } 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
Cú pháp Set Attr; int FDNum; FD * F; int Cap; Set Key;
Ý 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)
Cú pháp
inline RSC() {Reset();}
inline RSC(const RSC &r) { Reset();
Copy(r); }
Cú pháp ~RSC() { if (F != NULL) { delete [] F; F = NULL; } }
Ý 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
Cú pháp
inline void Renew()
Ý 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
Cú pháp 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
Toán tử gán
Cú pháp
void Copy(const RSC & r) { Attr = r.Attr;
FDNum = r.FDNum; // so PTH Cap = r.Cap; // Capacity Key = r.Key; delete [] F; if (r.F == NULL) F = NULL; else { F = new FD[Cap];
for(int i = 0; i < FDNum; ++i)
F[i] = r.F[i];
}
Mở rộng vùng chứa lớp lược đồ quan hệ RSC
Cú pháp
void Extend() {
int newCap = Cap + __UNIT; FD *g = new FD[newCap];
for(int i = 0; i < FDNum; ++i) g[i] = F[i];
Cap = newCap; delete [] F; F = g;
}
Ý nghĩa: Mở rộng vùng chứa lớp lược đồ quan hệ RSC
Chèn mới
Cú pháp
void Ins(const Set & ls, const Set & rs) { 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(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) {
y += F[i].GetRS(); mark[i] = 1; ++used; } } } if (used == 0) break; } return y; }
Ý nghĩa: Tạo phụ thuộc hàm của lược đồ quan hệ RSC
Cú pháp
Set FindKey() { Set k = Attr;
for (char c = 'A'; c <= 'Z'; ++c) { if (k.Has(c)) { k.Del(c); if (!(Closure(k).Has(c))) k.Ins(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
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
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 <iostream> #include <fstream> #include <bitset> using namespace std;
const int __SETSIZE = 26; const int __UNIT = 16;
typedef bitset<__SETSIZE> BS;
class RSC { 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(); } Set FindKey() { Set k = Attr;
for (char c = 'A'; c <= 'Z'; ++c) { if (k.Has(c)) { k.Del(c); if (!(Closure(k).Has(c))) k.Ins(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);
}
inline bool IsSuperkey(const Set &x) {
if (!(x <= Attr)) return false; if (Key <= x) return true;
return Attr <= Closure(x); }
inline bool IsSuperkey(const string s) {
return IsSuperkey(Set(s)); }
if (!IsSuperkey(x)) return false; Set k = x;
for (char c ='A'; c <= 'Z'; ++c) { if (k.IsIn(c)) { k.Del(c); if (Closure(k).IsIn(c)) return false; k.Ins(c); } } return true; }
inline bool IsKey(const string s) { return IsKey(Set(s)); } void TestRSC() { RSC r; r.Read("K.txt"); r.Show("\n r: ");
cout << "\n Key : " << r.GetKey();
} main() { TestRSC(); cout << "\n T H E E N D ."; return 0; } Kết quả ra màn hình
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,
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 <iostream> #include <fstream> #include <bitset> using namespace std;
const int __SETSIZE = 26; const int __UNIT = 16;
typedef bitset<__SETSIZE> BS;
class RSC { 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(); }
public:
inline RSC() {Reset();}
inline RSC(const RSC &r) { Reset(); Copy(r); } ~RSC() { if (F != NULL) { delete [] F; F = NULL; } }
inline void Renew() { Reset(); if (F != NULL) delete [] F; F = NULL; } // Renew private:
void Copy(const RSC & r) {
Attr = r.Attr; // Tap thuoc tinh
FDNum = r.FDNum; // so PTH
Cap = r.Cap; // Capacity
Key = r.Key; delete [] F; if (r.F == NULL) F = NULL; else { F = new FD[Cap];
for(int i = 0; i < FDNum; ++i)
F[i] = r.F[i];
}
}
public:
inline void operator =(const RSC & r) {Copy(r);}
inline int GetFDNum() const {return FDNum;}
inline Set GetKey() const {return Key;}
void Extend() {
int newCap = Cap + __UNIT; FD *g = new FD[newCap];
for(int i = 0; i < FDNum; ++i) g[i] = F[i]; Cap = newCap; delete [] F; F = g; }
void Ins(const Set & ls, const Set & rs) { 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(string ls, string rs) {Ins(Set(ls), Set(rs));}
void Norm() { int j = -1; int k;
for (int i = 0; i < FDNum; ++i) {
if (F[i].GetRS().Empty()) continue; ++j; F[j] = F[i]; for (int k = 0; k < j; ++k) { if (F[k].GetLS() == F[i].GetLS()) { F[k].AddRS(F[i].GetRS()); --j; break; } } } FDNum = j+1; Attr.Reset();
for (int i = 0; i < FDNum; ++i) { Attr += F[i].GetLR();
} }
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) { y += F[i].GetRS(); mark[i] = 1; ++used; } } } if (used == 0) break; } return y; }
inline Set Closure(const string s, int k = -1) { return Closure(Set(s),k);
}
Set FindKey() { Set k = Attr;
for (char c = 'A'; c <= 'Z'; ++c) { if (k.Has(c)) { k.Del(c); if (!(Closure(k).Has(c))) k.Ins(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);
}
if (!(x <= Attr)) return false; if (Key <= x) return true;
return Attr <= Closure(x); }
inline bool IsSuperkey(const string s) {
return IsSuperkey(Set(s)); }
bool IsKey(const Set &x) { if (!IsSuperkey(x))
return false; Set k = x;
for (char c ='A'; c <= 'Z'; ++c) { if (k.IsIn(c)) { k.Del(c); if (Closure(k).IsIn(c)) return false; k.Ins(c); } } return true; }
inline bool IsKey(const string s) { return IsKey(Set(s));
}
bool Derive(const FD & g, int k = -1) {
return (Closure(g.GetLS(),k) >= g.GetRS()); }
bool Derive(string ls, string rs, int k = -1) { return Derive(FD(ls,rs),k);
} // Derive
void NonRedundant() {
for(int i = FDNum-1; i >= 0; --i) { if (Derive(F[i],i)) { if (FDNum-1 > i) { F[i] = F[FDNum-1]; } --FDNum; } } }
void Read(const char * fn) { ifstream f(fn);
cerr << "\n Unable open in file " << fn; return; } 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])) rs += s[i]; } Ins(ls,rs); // New FD ls -> rs } f.close(); Norm(); Show("\n Read: "); NonRedundant(); SetKey(); }
inline bool IsBCNF() {
for (int i = 0; i < FDNum; ++i) { if (!IsSuperkey(F[i].GetLS())) return false; } return true; } void Print(string msg = "") { cout << msg;
Attr.Print("\n Attribute Set: "); Key.Print("\n Key: ");
cout << "\n Functional Dependencies: "; for (int i = 0; i < FDNum; ++i) {
cout << "\n " << i << ". "; F[i].Print();
}
friend ostream & operator <<(ostream & os, const RSC & s) { os << "\n Attribute Set: ";
os << s.Attr;
os << "\n Functional Dependencies: "; for (int i = 0; i < s.FDNum; ++i)
os << "\n " << i << ". " << s.F[i]; return os;
}
void Show(string msg = "") {