2022-03-05 符号表的应用(黑名单,白名单,CSV文件构造符号表,构建查询索引符号表,构建文件查询索引符号表)C++实现

符号表

符号表就是set和map,在c++中有基于红黑树实现的map,set,以及基于hash函数实现的unordered_map,unordered_set。

本文代码用到的符号表是我自己的实现,根据《算法4》的实现方法。

黑名单,白名单

黑名单就是名单上有的就过滤掉,输出名单上没有的。

白名单就是输出名单上有的,名单上没有的过滤掉。

CSV文件构造符号表

csv文件是一种以“,”为分隔符的格式化的储存文件,我们可以通过指定csv文件中的两个列来构建一个对应符号表。

查询索引符号表

符号表不一定是一对一,也可能是一对多,比如水果可以对应:苹果,香蕉,梨,菠萝,荔枝,西瓜等。根据这样规则的符号表就是查询索引表。

文件查询索引符号表

就是将文件内容当作key,将文件名当作val,类似文件搜索时,用文件的内容查看含有此内容的文件。

实现难点

这里最easy的难点是CSV文件的分隔符“,”,因为C++的流默认是用空格或换行符截断,同时C++没有
string 的 splite() 方法,好在有 getline() 函数,可以指定分隔符。

我遇到的比较困难的问题是做索引符号表,其结构是hashmap<string, vector<string>>,在我的hashmap实现中无法返回vector的引用,因为C++没有null类型,在hashmap不含有某个key的时候,get()函数返回为{ false, val() },这种 val() 右值无法转换为引用。

没有引用就无法插入元素。所以,只能引入令人头痛的指针。变成hashmap<string, vector<string>*>,的结构,解决了问题。只不过函数最后要delete掉所有new出来的内存。

性能问题

测试遇到一个含有3M大小的txt文件,构建查询索引符号表的时候,需要3,4秒才能完成,慢的令我怀疑我是否是用的C++,如果只有几万,几十万个数据,就慢成这样,我为啥用C++?

经过单步调试,发现问题出现在hashmap的增长方法,它需要不停的增长,导致不停的拷贝重建。如同vector 的增长问题,如果能事先预测hashmap到底有多少元素,就能解决。lookUpIndex() 函数中hashmap构建的注释部分有所体现。

以下是参考代码

    //输出流去重复
    void DeDup()
    {
        ST::hashSet<std::string> set;
        std::string keys;
        while (std::cin >> keys)
        {
            if (!set.contains(keys))
            {
                set.add(keys);
                std::cout << keys << " ";
            }
        }
    }
    // 白名单
    void whiteFilter(const std::string &file)
    {
        ST::hashSet<std::string> set;
        std::string keys;
        std::ifstream fileword(file);
        while (fileword >> keys)
        {
            set.add(keys);
        }
        fileword.close();
        while (std::cin >> keys)
        {
            if (set.contains(keys))
            {
                std::cout << keys << " ";
            }
        }
    }

    // 黑名单
    void blackFilter(const std::string &file)
    {
        ST::hashSet<std::string> set;
        std::string keys;
        std::ifstream fileword(file);
        while (fileword >> keys)
        {
            set.add(keys);
        }
        fileword.close();
        while (std::cin >> keys)
        {
            if (!set.contains(keys))
            {
                std::cout << keys << " ";
            }
        }
    }

    // CSV文件构造符号表,参数:CSV文件名,key的下标,value的下标
    void lookUpCsv(const std::string &file, const std::string &kField, const std::string &vField)
    {
        int keyField = std::stoi(kField);
        int valField = std::stoi(vField);
        std::ifstream files(file);
        std::stringstream words;
        ST::LPHashST<std::string, std::string> st;
        std::vector<std::string> tokens;
        tokens.reserve(8);
        std::string line;
        std::string word;
        while (std::getline(files, line))
        {
            // std::stringstream words(line);
            words.str(line);
            while (std::getline(words, word, ','))
            {
                tokens.push_back(word);
            }
            st.put(tokens[keyField], tokens[valField]);
            tokens.clear();
            words.clear();
        }
        files.close();
        while (std::cin >> word)
        {
            std::pair<bool, std::string> temp = st.get(word);
            if (temp.first)
            {
                std::cout << temp.second << "\n";
            }
        }
    }

    //构建查询索引符号表,参数为数据文件名,分隔符
    void lookUpIndex(const std::string &files, const std::string &split)
    {
        std::ifstream file(files);
        std::stringstream line;
        std::vector<std::string> keyVec;
        keyVec.reserve(32);
        char sp = split.at(0);
        ST::LPHashST<std::string, std::vector<std::string> *> st; //(12289);
        ST::LPHashST<std::string, std::vector<std::string> *> ts; //(393241);
        std::string words;
        std::string word;
        std::string val;
        std::string key;
        while (std::getline(file, words))
        {
            line.str(words);
            while (std::getline(line, word, sp))
            {
                keyVec.push_back(word);
            }
            key = keyVec[0];
            for (int i = 1; i != keyVec.size(); ++i)
            {
                val = keyVec[i];
                if (!st.contains(key))
                {
                    st.put(key, new std::vector<std::string>());
                    st.get(key).second->reserve(16);
                }
                if (!ts.contains(val))
                {
                    ts.put(val, new std::vector<std::string>());
                    ts.get(val).second->reserve(16);
                }
                st.get(key).second->push_back(val);
                ts.get(val).second->push_back(key);
            }
            keyVec.clear();
            line.clear();
        }
        file.close();
        std::string query;
        while (std::getline(std::cin, query))
        {
            if (st.contains(query))
            {
                for (auto &&i : *st.get(query).second)
                {
                    std::cout << " " << i << "\n";
                }
            }
            if (ts.contains(query))
            {
                for (auto &&i : *ts.get(query).second)
                {
                    std::cout << " " << i << "\n";
                }
            }
        }
        auto delstVec = st.keyVec();
        auto deltsVec = ts.keyVec();
        for (auto &&i : delstVec)
        {
            delete st.get(i).second;
        }
        for (auto &&i : deltsVec)
        {
            delete ts.get(i).second;
        }
    }

    //构建查询索引符号表,参数为数据文件名的数量-1,数据文件名字符组。
    void fileIndex(int argc, char *argv[])
    {
        ST::LPHashST<std::string, ST::hashSet<std::string> *> st;
        std::string filename;
        std::string word;
        std::fstream file;
        for (int i = 1; i != argc; ++i)
        {
            file.open(argv[i]);
            while (file >> word)
            {
                if (!st.contains(word))
                {
                    st.put(word, new ST::hashSet<std::string>());
                }
                st.get(word).second->add(argv[i]);
            }
            file.close();
        }
        std::string query;
        while (std::cin >> query)
        {
            if (st.contains(query))
            {
                auto prtvec = st.get(query).second->keyVec();
                for (auto &&i : prtvec)
                {
                    std::cout << " " << i << "\n";
                }
            }
        }
        auto delvec = st.keyVec();
        for (auto &&i : delvec)
        {
            delete st.get(i).second;
        }
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不停感叹的老林_<C 语言编程核心突破>

不打赏的人, 看完也学不会.

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值