数据库——C++实现求最小函数依赖集


一、最小函数依赖集

如果函数依赖集F满足下列条件,则称F为最小函数依赖集或最小覆盖。
① F中的任何一个函数依赖的右部仅含有一个属性;
② F中不存在这样一个函数依赖X→A,使得F与F-{X→A}等价;
③ F中不存在这样一个函数依赖X→A,X有真子集Z使得F-{X→A}∪{Z→A}与F等价。

定理及原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、C++代码实现求最小函数依赖集

思路与步骤

分三步:

步骤一:拆分

检查函数依赖:把每个右边项有k元属性组的式子改为k个单元函数
例:A->BC 应该拆分为为 A->B 和 A->C

步骤二:去掉重复的传递函数依赖

逐一检查F中的各函数依赖FDi:X->A,令G = F - {X->A},若A属于XG+,则从F中去掉此函数依赖
例:B->A,B->C, C->A,其中“B->A”可由“B->C和C->A”推出,因此B->A是多余的,应去掉

步骤三:逐一检查每个函数依赖来去掉部分函数依赖

逐一取出F中各函数依赖FDi:X->A,设X = B1 B2 … Bm,m≥2,逐一考查Bi(i=1,2,…,m),
若A属于(X-Bi)F+,则以X-Bi取代X。[即A和Bi无关]
例:C->A,函数依赖ACD->B中的属性A是多余的,去掉A得CD→B

C++代码

//求函数依赖集F的最小依赖集
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

//计算函数依赖右部(箭头右边)的属性个数
int rightCount(string str) {
    int i = str.find('>');      //记录箭头的位置
    return str.size() - 1 - i;  //返回箭头右边属性个数
}

//计算函数依赖左部(箭头左边)的属性个数
int leftCount(string str) {
    int i = str.find('-');  //记录箭头的位置
    return i;       //返回箭头左边属性个数
}

//步骤一:拆分
//检查函数依赖:把每个右边项有k元属性组的式子改为k个单元函数
//例:A->BC 应该拆分为为 A->B 和 A->C
vector<string> step1(const vector<string> &F) {
    vector<string> F0 = F;
    //从后往前遍历,这样删除函数依赖时不会影响到遍历的下标i所对应的元素
    for(int i = F.size() - 1; i >= 0; i--) {
        if(rightCount(F[i]) > 1) {  //如果右部的属性大于一个
            string leftStr = F[i].substr(0,leftCount(F[i]));    //截取箭头左边的属性
            int k = F[i].size() - 1;
            //将拆开后的函数依赖放入集合F中
            for(int j = 0; j < rightCount(F[i]); j++) {\
                string str_temp = leftStr;
                str_temp += "->";
                str_temp += F[i][k--];
                F0.push_back(str_temp);
            }
            //将原来的函数依赖去除掉
            //创建迭代器并指向改函数依赖在集合中的位置
            auto iter = F0.begin();
            iter += i;
            F0.erase(iter);
        }
    }
    return F0;
}

//检查XG中是否包含substr
bool judge(string sub_str, string XG) {
    for(int i = 0; i < sub_str.size(); i++) {
        if(XG.find(sub_str[i]) == XG.npos)   return false;
    }
    return true;
}

//步骤二:去掉重复的传递函数依赖
//逐一检查F中的各函数依赖FDi:X->A,令G = F - {X->A},若A属于XG+,则从F中去掉此函数依赖
//例:B->A,B->C, C->A,其中“B->A”可由“B->C和C->A”推出,因此B->A是多余的,应去掉
vector<string> step2(vector<string> &F) {
    //从后往前遍历,这样删除函数依赖时不会影响到遍历的下标i所对应的元素
    for(int i = F.size() - 1; i >= 0; i--) {
        string X = F[i].substr(0,leftCount(F[i]));    //截取箭头左边的属性
        vector<string> G = F;
        //迭代器指向当前遍历的函数依赖
        auto iter = G.begin();
        iter += i;
        G.erase(iter);  //G = F - {X->A}
        string XG = X;

        for(int k = 0; k < G.size(); k++) {
            if(judge(G[k].substr(0, leftCount(G[k])), XG) && XG.find(G[k][G[k].size() - 1]) == XG.npos) {
                XG += G[k][G[k].size() - 1];
                k = -1;
            }
        }
        if(XG.find(F[i][F[i].size() - 1]) != XG.npos) {
            //更新F
            auto iter2 = F.begin();
            iter2 += i;
            F.erase(iter2);
        }
    }
    return F;
}

//步骤三:逐一检查每个函数依赖来去掉部分函数依赖
//逐一取出F中各函数依赖FDi:X->A,设X = B1 B2 … Bm,m≥2,逐一考查Bi(i=1,2,…,m),若A属于(X-Bi)F+,则以X-Bi取代X。[即A和Bi无关]
//例:C->A,函数依赖ACD->B中的属性A是多余的,去掉A得CD→B
vector<string> step3(vector<string>  &F) {
    for(int i = 0; i < F.size(); i++) {
        if(leftCount(F[i]) == 1) {
            char left = F[i][0];
            char right = F[i][F[i].size() - 1];
            for(int j = 0; j < F.size(); j++) {
                //只需要检查左部不是单个属性的函数依赖
                if(leftCount(F[j]) > 1) {
                    //截取左边的属性
                    string str = F[j].substr(0, leftCount(F[j]));
                    if(str.find(left) != str.npos && str.find(right) != str.npos)
                        F[j].erase(F[j].find(right), 1);
                }
            }
        }
    }
    return F;
}

//求函数依赖集F的最小依赖集
vector<string> Minimum_Dependency_Set(vector<string> &F) {
    //依次执行三个步骤
    F = step1(F);
    F = step2(F);
    F = step3(F);
    return F;
}

//打印函数依赖集
void show(const vector<string> &F) {
    for(int i = 0; i <F.size(); i++) {
        if(i == F.size() - 1)
            cout << F[i];
        else
            cout << F[i] << ",";
    }
}

int main()
{
    vector<string> F;   //函数依赖集
    cout << "输入函数依赖集F(箭头采用“->”形式,例:A->B;输入#号终止输入)" << endl;
    cout << "------请输入:" ;
    string str;
    while(cin >> str) {
        if(str == "#")  break;
        F.push_back(str);
    }
    cout << endl;
    //打印原始函数依赖集
    cout << "原始函数依赖集F = {";
    show(F);
    cout << "}" << endl;

    F = Minimum_Dependency_Set(F);
    cout << endl;

    //打印最小函数依赖集
    cout << "最小函数依赖集F(min) = {";
    show(F);
    cout << "}" << endl;
    return 0;
}

三、运行结果

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值