分解的依赖保持性判定
----------------------------------------------------------------------------------------------------------------------------------------------------------
定义:对于R(U,F), R(U,F)的分解p={R1(U1,F1),(U2,F2),...,Rk(Uk,Fk)},其中,F1,F2,...Fi,分别对应为F中在R1,R2,...Rk上的函数依赖集合。
令G=F1 U F2 U F3...U Fk(多个函数依赖集合求并集),若F+==G+(其实就是如果G等于F)的话,则分解p保持函数依赖。
实质: G=F1 U F2 U F3...U Fk,判断G和原函数依赖F是否等价输入:R上的函数依赖集F以及R的一个分解 p={{R1,F1},{R2,F2},...,{Rk,Fk}}
输出:判断分解p的依赖保持性
步骤:
第0步,初始化。输入R上的函数依赖集F以及R的一个分解 p={{R1,F1},{R2,F2},...,{Rk,Fk}},求出G
第1步,检验F上的任意一个函数依赖是否能够由G通过Armstrong公理导出,及任意是否Y属于X关于G的闭包
第2步,检验G上的任意一个函数依赖是否能够由F通过Armstrong公理导出,及任意是否Y属于X关于F的闭包
第3步,若第1步和第2步均满足,则F的闭包=G的闭包
----------------------------------------------------------------------------------------------------------------------------------------------------------
那么,F1、F2、F3...Fk是什么意思以及 G=F1 U F2 U F3...U Fk如何求得呢?
Fi是R(U,F)的函数依赖集合F在各个分解Ui上的投影,G也就是全部F在各个分解Ui上的投影的并集。
π(Ui)F表示F在某个分解Ui上的投影,它是一个函数依赖集合(里面的元素是函数依赖X->Y),X,Y均属于Ui,并且形如X->Y函数依赖都在F的闭包F+上,等价于Y属于X关于F的闭包。
所以要求G,首先就要求F在各个分解上的投影。然后并起来,就是G了。这是第0步的工作。之后就按照上面介绍的步骤来就是了。
---------------------------------------------------------------------------------------------------------------------------------------
程序:
//分解的依赖保持性判定
//定义:若R(U,F), R(U,F)的分解p={R1(U1,F1),(U2,F2),...,Rk(Uk,Fk)},F+=F1 U F2 U F3...U Fk,
//其中,F1,F2,...Fi,分别对应为,F中在R1,R2,...RK上的函数依赖集合。则分解p保持函数依赖
//实质: G=F1 U F2 U F3...U Fk,判断G和原函数依赖F是否等价
//输入:R上的函数依赖集F以及R的一个分解 p={{R1,F1},{R2,F2},...,{Rk,Fk}}
//输出:判断分解p的依赖保持性
#include <iostream>
#include <string>
using namespace std;
struct FunctionDependence//函数依赖
{
string X;//决定因素
string Y;
};
void InitFD (FunctionDependence FD[],int n)
{
//函数依赖关系初始化
int i;
string x,y;
cout<<"请输入F中的函数依赖(决定因素在左,被决定因素在右)"<<endl;
//输入函数依赖集合F
for (i=0;i<n;i++)
{
cin>>x>>y;
FD[i].X=x;
FD[i].Y=y;
}
cout<<"函数依赖集合F:";
cout<<"F={" ;
for (i=0;i<n;i++)
{
//显示已知的函数依赖集合F
cout<<FD[i].X<<"->"<<FD[i].Y;
if (i<n-1)cout<<", ";
}
cout<<"}"<<endl;
}
bool Match(string a,string b)//判断两个字符串是否匹配
{
bool flag=false;
int length1=a.length();
int length2=b.length();
int count=0;
if (length1==length2)
{
int i=0,j=0;
//字符串每一位是否相等
for (i=0;i<length1;i++)
{
if(a[i]==b[i])count++;
}
if (count==length1)
flag=true;
}
return flag;
}
bool IsIn(string f,string zz)//能够判断F中决定因素f里所有的因素是否在X中,但这样可能导致结果出现重复
{
bool flag1=false;
int len1=f.length();
int len2=zz.length();
int k=0,t=0,count1=0;
for (k=0;k<len1;k++)
{
for (t=0;t<len2;t++)
{
if (f[k]==zz[t])
{
//flag1=true;break;
count1++;
}
}
}
if (count1==len1)
{
flag1=true;
}
else flag1=false;
return flag1;
}
string CutAndSort(string mm)//将最终得到的闭包去除其中重复的元素,并且进行排序
{
int size=mm.length();
int kk=0,ii=0;;
string closure;
int a[200]={0};//用来记录各个命题出现的次数
for(kk=0;kk<size;kk++)
{
a[(int)mm[kk]]++;//强制转换类型,储存各个因素的次数
}
for (ii=0;ii<200;ii++)
{
if (a[ii]>=1)//cout<<(char)ii;
closure+=(char)ii;
}
return closure;
}
string X_Fn(FunctionDependence FD[],int n,string &xx)
{
string yy=xx;
for (int i=0;i<n;i++)
{
if (IsIn(FD[i].X,yy)==true)
{
xx+=FD[i].Y;
}
}
yy=CutAndSort(yy);
xx=CutAndSort(xx);
//cout<<"yy="<<yy;
//cout<<" xx="<<xx<<endl;
if (xx!=yy)
{
X_Fn(FD,n,xx);//递归
}
return xx;
}
string FD(FunctionDependence FD[],int n,string xx)
{
int i;
//cout<<"\n"<<xx<<"关于F的闭包:{";
//求X关于F的闭包
/*
for (i=0;i<n;i++)
{
if (IsIn(FD[i].X,xx)==true)
{
if (IsIn(FD[i].Y,xx)==false)//避免加上重复的元素
xx+=FD[i].Y;
//假如有传递性
string temp_str=FD[i].Y;
for (int ii=0;ii<n;ii++)
{
if (Match(temp_str,FD[ii].X)==true)
{
xx+=FD[ii].Y;
if (FD[i].X!=FD[ii].Y)//重中之重!!!
temp_str=FD[ii].Y;
}
}
}
}*/
//cout<<X_Fn(FD,n,xx);
//cout<<"}\n";
return X_Fn(FD,n,xx);
}
string char2string(char mychar,string mystring)//将单个char转换成string类型
{
mystring="a";//仅仅只是赋予一个初始值
mystring[0]= mychar;
return mystring;
}
int main()
{
//第0步,初始化。输入R上的函数依赖集F以及R的一个分解 p={{R1,F1},{R2,F2},...,{Rk,Fk}},求出G
//0.0初始化
cout<<"请输入关系模式R(中间无间隔,无回车)"<<endl;
string A;
cin >> A;
int lengthR = A.length();
cout<<"关系模式R={";
for (int i = 0;i<lengthR;i++)
{
cout << A[i] ;
if (i<lengthR-1)cout<<",";
}
cout<<"}"<<endl;
int count = 0;
string R[lengthR+20];
cout<<"输入R的一个分解p(以0结束)\n";
while (cin >> R[count])//当输入的字符串不在R中时自动跳出
{
if (IsIn(R[count],A) == false) break;
count++;
}
cout<<"p={";
for (int i = 0;i<count;i++)
{
cout << R[i] ;
if (i<count-1)cout<<",";
}
cout<<"}";
int N;
cout<<"\n请输入F中函数依赖的组数:";
cin>>N;
FunctionDependence fd[N];
InitFD(fd,N);
//0.1求出G
FunctionDependence G[N+30];//用来储存新的函数依赖
string temp;
//依此求得函数依赖集合F在各个分解上的投影
int G_size=0;//新函数依赖集合G的大小
for (int i=0;i<count;i++)
{
//下面两层循环是排列出Ri中所有的组合,例如R3=BCD,则可能的组合有B->C,B->D,C->D,理论上有n*(n-1)/2种情况
for (int j=0;j<R[i].length();j++)
{
//得到X关于F的闭包
string temp_A="a";//a仅仅只是一个初始值而已,没有其他意义
temp_A=char2string(R[i][j],temp_A);
temp=FD(fd,N,temp_A);//R[i][j]表示第i个分解的第j位,不知道这样表示成二维数组的形式可不可以 !
for (int k=0;k<R[i].length();k++)
{
if (j==k)continue;
string temp_B="b";
temp_B=char2string(R[i][k],temp_B);
if (IsIn(temp_B,temp)==true)
{
G[G_size].X=R[i][j];
G[G_size].Y=R[i][k];//得到的集合,左边右边都是原子属性
G_size++;
}
}
}
}
//显示G
cout<<"F在各个分解上投影的并集G={";
for (int i=0;i<G_size;i++)
{
cout<<G[i].X<<"->"<<G[i].Y;
if (i<G_size-1)cout<<", ";
}
cout<<"}"<<endl;
//第1步,检验F上的任意一个函数依赖是否能够由G通过Armstrong公理导出,及任意是否Y属于X关于G的闭包
bool first_flag=0;
int first_count=0;
for (int i=0;i<N;i++)
{
if (IsIn(fd[i].Y,FD(G,G_size,fd[i].X))==true)//Y属于X关于F的闭包 G,G_size
{
first_count++;
cout<<fd[i].Y<<"属于"<< fd[i].X<<"对于G的闭包"<<FD(G,G_size,fd[i].X)<<endl;
}
}
if (first_count==N)
{
first_flag=1;cout<<"F上的任意一个函数依赖能够由G通过Armstrong公理导出\n"<<endl;
}
//第2步,检验G上的任意一个函数依赖是否能够由F通过Armstrong公理导出,及任意是否Y属于X关于F的闭包
bool second_flag=0;
int second_count=0;
for (int j=0;j<G_size;j++)
{
if (IsIn(G[j].Y,FD(fd,N,G[j].X))==true)//Y属于X关于F的闭包
{
second_count++;
cout<<G[j].Y<<"属于"<< G[j].X<<"对于G的闭包"<<FD(fd,N,G[j].X)<<endl;
}
}
if (second_count==G_size)
{
second_flag=1;cout<<"G上的任意一个函数依赖能够由F通过Armstrong公理导出\n"<<endl;
}
//第3步,若第1步和第2步均满足,则F的闭包=G的闭包
if (first_flag==1&&second_flag==1)cout<<"F的闭包==G的闭包,分解p具有依赖保持性!"<<endl;
else cout<<"F的闭包!=G的闭包,分解p不具有依赖保持性!"<<endl;
return 0;
}
结果: