满足第三范式3NF的函数依赖保持分解算法
----------------------------------------------------------------------------------------------------------------------------------------------------------
输入:关系模式R和函数依赖集合F
输出:结果为满足第三范式的一个依赖保持的分解
条件:
1.如果R中有某些属性与F的最小覆盖Fmin中的左边右边都没有关系,则这个(些)属性构成一个关系模式。如果没有就进行2
2. 如果Fmin中有一个函数依赖涉及R中的所有属性,则输出R。否则,进行3
3.对于Fmin,其中有X->Ai这样的函数依赖,则添加XAi到一个分解集合p中,但是当X->A1,X->A2,...,X->An时(即X可与决定Fmin中多个属性),用XA1A2...An来替换之前的XAi
----------------------------------------------------------------------------------------------------------------------------------------------------------
回顾一下什么是1NF,2NF,3NF以及BCDF:http://blog.csdn.net/scnujack/article/details/6539642
----------------------------------------------------------------------------------------------------------------------------------------------------------
程序:
//满足第三范式3NF的函数依赖保持分解算法
//输入:关系模式R和函数依赖集合F
//输出:结果为满足第三范式的一个依赖保持的分解
//条件:1.如果R中有某些属性与F的最小覆盖Fmin中的左边右边都没有关系,则这个(些)属性构成一个关系模式。如果没有就进行2
//2. 如果Fmin中有一个函数依赖涉及R中的所有属性,则输出R。否则,进行3
//3.对于Fmin,其中有X->Ai这样的函数依赖,则添加XAi到一个分解集合p中,但是当X->A1,X->A2,...,X->An时(即X可与决定Fmin中多个属性),用XA1A2...An来替换之前的XAi
#include <iostream>
#include <string>
using namespace std;
struct FunctionDependence//函数依赖
{
string X;//决定因素
string Y;
};
struct Hash//散列
{
int num;//用来记录字符串出现的次数
string s;
};
void Init (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<<"函数依赖集合";
cout<<"F={" ;
for (i=0;i<n;i++)
{
//显示已知的函数依赖集合F
cout<<FD[i].X<<"->"<<FD[i].Y;
if (i<n-1)cout<<", ";
}
cout<<"}"<<endl;
}
bool CharIsIn(char f, string zz)
{
bool flag = false;
int len = zz.length();
int k = 0, count1 = 0;
for (k = 0;k<len;k++)
{
if (f == zz[k])
{
flag= true;;
}
}
return flag;
}
string CutAndSort(string mm)//将最终得到的闭包去除其中重复的元素,并且进行排序
{
int size=mm.length();
string ss="\0";
int kk=0,ii=0;;
int a[200]={0};//用来记录各个命题出现的次数
for(kk=0;kk<size;kk++)
{
a[(int)mm[kk]]++;//强制转换类型,储存各个因素的次数
}
for (ii=0;ii<200;ii++)
{
if (a[ii]>=1)
ss+=(char)ii;
}
return ss;
}
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 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);
if (xx!=yy)
{
X_Fn(FD,n,xx);//递归
}
return xx;
}
string FD_Fun(FunctionDependence FD[],int n,string xx)
{
//求X关于F的闭包
return X_Fn(FD,n,xx);
}
//从函数依赖集F中删除某个依赖关系 left->right
void Cut(FunctionDependence FD[],int n,string left,string right,FunctionDependence Dyna[])
{
int i=0,j=0,count=0;
for (i=0;i<n;i++)
{
if((FD[i].X==left)&&(FD[i].Y==right))
{
}
else
{
Dyna[count].X=FD[i].X;
Dyna[count].Y=FD[i].Y;
count++;
}
}
cout<<"去掉"<<left<<"->"<<right;
cout<<"后的函数依赖集F:"<<endl;
cout<<"F={" ;
for(j=0;j<count;j++)
{
cout<<Dyna[j].X<<"->"<<Dyna[j].Y;
if (j<count-1)cout<<",";
}
cout<<"}"<<endl;
}
bool RA(FunctionDependence a,FunctionDependence b)//判断冗余属性
{
if ((IsIn(a.X,b.X)==true)&&(a.Y==b.Y))
{
return true;
}
else return false;
}
string StringCutChar(char f, string zz) //从中去掉一个属性
{
int len = zz.length();
int k = 0;
string tt;
for (k = 0;k<len;k++)
{
if (f == zz[k])
{
}
else
{
tt+=zz[k];
}
}
return tt;
}
FunctionDependence Dyna[200];
int Fmin_Size;
void CutSameFD(FunctionDependence FD[],int n)//除去重复的函数依赖
{
FunctionDependence Dyna1[n+20];
FunctionDependence Dyna2[n+20];
int i=0,j=0,k=0,count=0,count1=0;//count2=0;
for (i=0;i<n;i++)
{
for (j=0;j<count;j++)
{
if((FD[i].X==FD[j].X)&&(FD[i].Y==FD[j].Y))//有函数依赖重复
{
break;//跳过当前的函数依赖
}
}
if (j==count)
{
Dyna1[count].X=FD[i].X;
Dyna1[count].Y=FD[i].Y;
count++;
}
}
cout<<"去掉重复后的函数依赖集F="<<"{";
for (k=0;k<count;k++)
{
//去掉重复后的函数依赖集
cout<< Dyna1[k].X<<"->"<<Dyna1[k].Y;
if (k<count-1)cout<<",";
}
cout<<"}"<<endl;
for (k=0;k<count;k++)
{
//从第一个函数依赖X→Y开始将其从F中去掉,
Cut( Dyna1,count,Dyna1[k].X,Dyna1[k].Y,Dyna2);
//然后在剩下的函数依赖中求X的闭包X+,看X+是否包含Y
cout<<Dyna1[k].X<<"关于F的闭包:";
cout<<FD_Fun(Dyna2,count,Dyna1[k].X);//在剩下的函数依赖中求X的闭包X+
if(IsIn(Dyna1[k].Y,FD_Fun(Dyna2,count,Dyna1[k].X))==true)//在闭包中
{
cout<<"\n"<<Dyna1[k].X<<"->"<<Dyna1[k].Y<<"冗余"<<endl;
}
else
{
cout<<"\n"<<Dyna1[k].X<<"->"<<Dyna1[k].Y<<"不冗余"<<endl;
Dyna[count1].X=Dyna1[k].X;
Dyna[count1].Y=Dyna1[k].Y;
count1++;
}
}
cout<<"\n去冗余函数依赖后的函数依赖集F={";
for (i=0;i<count1;i++)
{
cout<<Dyna[i].X<<"->"<<Dyna[i].Y;
if (i<count1-1)cout<<",";
}
cout<<"}"<<endl;
//去掉冗余属性
for (i=0;i<count1;i++)
{
for (j=0;j<Dyna[i].X.length();j++)
{
//X-Bj
string temp_x=StringCutChar((Dyna[i].X)[j],Dyna[i].X);
if (IsIn(Dyna[i].Y,FD_Fun(Dyna,count1,temp_x))==true)//即X->A,X=B1B2..Bm,A属于{X去掉某个其中的属性Bi的闭包}
{
Dyna[i].X= temp_x;
}
}
}
//求得最小覆盖
cout<<endl;
cout<<"最小覆盖Fm="<<"{";
for (k=0;k<count1;k++)
{
cout<<Dyna[k].X<<"->"<<Dyna[k].Y;
if (k<count1-1)cout<<",";
}
cout<<"}"<<endl;
Fmin_Size=count1;
}
void SingleR(FunctionDependence FD[],int n) //使F所有函数依赖的右部分解成单一属性
{
int lengthR=0,i=0,j=0,k=0;
static int D=n;
int count=0;
FunctionDependence DynamicFD[D+20];//建立新的空间来存储所有的函数依赖
cout<<"右侧属性单一化后的函数依赖集F为:"<<endl;
cout<<"F={" ;
for (i=0;i<n;i++)
{
lengthR=(FD[i].Y).size();
for (j=0;j<lengthR;j++)//将右部分解成单一属性,添加到属性集合的后面
{
DynamicFD[count].X=FD[i].X;
DynamicFD[count].Y= (FD[i].Y)[j];
count++;
}
}
for (k=0;k<count;k++)
{
cout<<DynamicFD[k].X<<"->"<<DynamicFD[k].Y;
if (k<count-1)cout<<", ";
}
cout<<"}"<<endl;
D=count;
CutSameFD(DynamicFD,D);
}
bool DinamicCompare(string a,Hash b[],int n)
{
int count_dc=0;
for (int i=0;i<n;i++)
{
if (a!=b[i].s)count_dc++;
}
if (count_dc==n) return true;
else return false;
}
void Fmin(FunctionDependence FD[],int n)//求最小覆盖
{
Init(FD,n);
SingleR(FD,n);
}
int main()
{
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 N;
cout<<"请输入F中函数依赖的组数:";
cin>>N;
//第一步:求出F的最小覆盖
FunctionDependence fd[N];
//FunctionDependence Dyna3[N+20];
Fmin(fd,N);
//第二步:如果R中有某些属性与F的最小覆盖Fmin中的左边右边都没有关系,则这个(些)属性构成一个关系模式。如果没有就进行2
int count_i = 0,count=0;
string R[lengthR+20];
Hash left_type[lengthR+20];//用来储存Fmin的不同决定因素
int temp1=0,l_type=0,l_num=0;
for (int n=0;n<Fmin_Size;n++)
{
if (DinamicCompare(Dyna[n].X,left_type,l_type)==false)//和之前的有相等的,跳过
{
continue;
}
for (int nn=0;nn<Fmin_Size;nn++)
{
if (Dyna[n].X==Dyna[nn].X)
{
l_num++;
left_type[l_type].s=Dyna[n].X;
left_type[l_type].num=l_num;//出现的次数
}
}
l_type++;
l_num=0;
}
int k=0;
bool my_flag=0;
for (int i = 0;i<lengthR;i++)
{
while (Dyna[k].X!="\0")
{
if (CharIsIn(A[i],Dyna[k].X)==false&&CharIsIn( A[i], Dyna[k].Y)==false)
{
count_i++;
}
else if (CutAndSort(Dyna[k].X+Dyna[k].Y)==CutAndSort(A))
{
cout<<"分解就是A本身"<< CutAndSort(A)<<endl;
my_flag=1;break;
}
k++;
}
if (count_i==Fmin_Size)
{
R[count]=A[i];
count++;
}
if (my_flag==1)break;
}
//3.对于Fmin,其中有X->Ai这样的函数依赖,则添加XAi到一个分解集合p中,但是当X->A1,X->A2,...,X->An时(即X可与决定Fmin中多个属性),用XA1A2...An来替换之前的XAi
if (my_flag==0)
{
for (int m=0;m<l_type;m++)
{
R[count]=left_type[m].s;//+Dyna[m].Y;
for (int aa=0;aa<Fmin_Size;aa++)
{
//if (aa==m)continue;
if (left_type[m].s==Dyna[aa].X)
{
R[count]+=Dyna[aa].Y;
}
}
count++;
}
cout<<"满足第三范式3NF的函数依赖保持分解p={";
for (int bb=0;bb<count;bb++)
{
cout<<R[bb];
if (bb<count-1)cout<<",";
}
cout<<"}"<<endl;
}
return 0;
}
其中求最小覆盖等函数,沿用或者部分改变自之前编写的函数,如有疑问可以查看之前的文章。