#求属性闭包的实现
属性闭包:
关系模式 R < U , F > R<U,F> R<U,F>中, U U U代表全部属性集合, U U U为一组函数依赖关系。
现设属性集 X X X属于 U U U,对 X X X求属性闭包,即为根据推导规则从属性集合 X X X推导出属性集合(闭包) X F + XF^+ XF+
###问题描述:
对于给定的属性集合U,函数依赖集F,都以string类型表示,求某一属性集合X的属性闭包
例题:U={ABCDE},F={A→B, B→C,DA->BC,A->BC,DB->C}, 求属性BC的闭包。
求属性闭包的算法
针对上述例题来讲:
- 令 X i = B C X_i=BC Xi=BC,求取 X i X_i Xi的子集(这里不包含空集而且子集划分为只要元素不同,不考虑顺序),为 B , C , B C B,C,BC B,C,BC,遍历函数依赖集找到左部为 X i X_i Xi的子集部分,找到把函数依赖的右部加入 P P P.
- 令 X i + 1 = X i U P X_{i+1}=X_iUP Xi+1=XiUP,判断 X i + 1 X_{i+1} Xi+1是否和 X i X_i Xi或者和 U U U相等,若相等跳出循环, X i + 1 X_{i+1} Xi+1即为所求闭包,不相等调到步骤1.
思路:
首先是分割字符串提取信息保存函数依赖关系。
对于函数依赖要明确的是如何存储函数依赖。
第一考虑的是用图的邻接矩阵来存储属性之间的依赖关系,但发现用图的思路去思考问题有错误的地方:若AD->C,并不能化为A->C,D->C;所以采用MultiMap保存映射关系。
A->DC 可以变为A->D,A->C
是因为在关系模式中属性列A有相等的两行,属性列DC都有对应位置相等的两行。
但DC->A,不能变化为D->A,C->A.
是因为在关系模式中要求属性列D和C同时有相等的两行时,属性列A也有相等的两行才成立。但D->A,C->A,成立的条件中没有同时的条件,所以上述是不相等的。
####MultiMap
与 map 类似,所不同的是它允许重复键.
基本使用方法:
1.定义:
multimap<string, string>Map;
2.插入:
Map.insert(make_pair("we","student"));
3.遍历:
for (multimap<string, string>::iterator it = Map.begin(); it != Map.end(); it++)
{
cout <<(*it).first<< endl;
cout << (*it).second << endl;
}
4.多值查找:
typedef std::multimap<string, string>::iterator it;
pair<it, it>res;
res = map.equal_range("we");
while (res.first != res.second)
{
cout << res.first->second << endl;
++res.first;
}
Note:
1.vector重载的赋值运算符必须要求顺序内容和长度都相等
2.二维数组的传地址问题:
//void Process(string F,int (*FD)[MaxLen])
void Process(string F, int FD[][MaxLen])
3.s.substr(0,5);
//获得字符串s中 从第0位开始的长度为5的字符串,默认时的长度为从开始位置到尾.
代码:
注:没有做输入非法处理,假定输入合法
#include<iostream>
#include<vector>
#include<map>
#include<boost/algorithm/string.hpp>
#include<string>
using namespace std;
using namespace boost;
const int MaxLen = 10;
class ClosePaket {
private:
string Attribute;
int len;
multimap<string, string>FD;
public:
/*初始化*/
void Init(string a)
{
Attribute = a;
sort(Attribute.begin(),Attribute.end());//便于排序
}
/*处理函数依赖关系,并将其保存到Map中
@param F: 函数依赖关系表示的字符串
@param FD:保存依赖关系的Map*/
void Process(string F)
{
vector<string>strVec;
split(strVec, F, is_any_of(","));//分割成A->BC
for (size_t i = 0; i < strVec.size(); i++)
{
vector<string>str;
cout << strVec[i] << endl;
//把连续多个分隔符当作一个token_compress_on
split(str, strVec[i], is_any_of("->"), token_compress_on);//分割成 A || BC
//其中这里str[0]为依赖关系的前部分(A),str[1]为依赖关系的后半部分(BC)
//cout << "size:" << str.size() << endl;
if (str.size() != 2)cout << "分割字符串出错!!" << endl;
FD.insert(make_pair(str[0], str[1]));
}
/*for (multimap<string, string>::iterator it = FD.begin(); it != FD.end(); it++)
{
cout << (*it).first << endl;
cout << (*it).second << endl;
}*/
}
/*求取dst的子串并返回子串数组vector*/
vector<string> SubString(string dst)
{
vector<string>sub;
for (size_t i = 0; i <dst.size(); i++)
{
for (size_t j = 1; j <= dst.size() - i; j++)
{
sub.push_back(dst.substr(i, j));
}
}
/*for (size_t i = 0; i < sub.size(); i++)
cout << sub[i] << endl;*/
return sub;
}
/*使tem中插入不重复字符
***在tem中插入tem中不曾出现的字符,而不是字符串
@param tem:被插入的字符串
@param x:要插入的字符串*/
void insert(string &tem,string x)
{
for (size_t i = 0; i < x.size(); i++)
{
int flag = 0;
for (size_t j = 0; j < tem.size(); j++)
{
if (tem[j] == x[i])flag = 1;
}
if (flag == 0)
tem += x[i];
}
}
/*求属性集X的闭包
返回属性闭包表示的字符串,若失败返回空串
1.判断init是否等于属性集总体
2.遍历Map寻找key为init的子集,找到则把value加到tem
3.判断tem和init是否相等
@param dst: 属性集*/
string GetClosePacket(string dst)
{
string init = dst;//init=x(i)
string tem;//tem=x(i+1)
while (true)
{
//判断是否等于属性集总体
if (init == Attribute) { return init; }
tem = "";
tem = init;
vector<string>sub = SubString(init);
for (size_t i = 0; i < sub.size(); i++)
{
//cout << "当前的键:" << sub[i] << endl;
typedef std::multimap<string, string>::iterator it;
pair<it, it>res;
res = FD.equal_range(sub[i]);
while (res.first != res.second)
{
//cout<<"找到的键值:"<< res.first->second << endl;
insert(tem,res.first->second);
//cout << "当前的tem值:" << tem << endl;
++res.first;
}
}
// 判断tem和init是否相等
sort(tem.begin(),tem.end());
sort(init.begin(),init.end());
if (tem == init) { return init; }
init = tem;
}
return "";
}
};
/*主函数*/
int main()
{
/*属性集Attribute*/
//char Attribute[] = { 'A','B','C','D','E' };
string a = "ABCDE";
string F = "AB->C,B->D,C->E,EC->B,AC->B";
ClosePaket cp;
/*初始化*/
cp.Init(a);
/*处理字符串F*/
cp.Process(F);
/*求属性AB的闭包*/
string res = cp.GetClosePacket("EC");
cout << "属性闭包为:" << res << endl;
system("pause");
return 0;
}