C++ 减少字符串比较的时间复杂性

C++ 减少字符串比较的时间复杂性,c++,string,C++,String,我有一个.txt文件,里面大概有一千多个单词和它们的定义。我已经编写了一个程序,从该文件中提取每行的第一个字,并根据用户输入的字符串进行检查: void checkWord(string input) { std::ifstream inFile; inFile.open("Oxford.txt"); if (inFile.is_open()) { string line; //there is a "using std::string" in

我有一个.txt文件,里面大概有一千多个单词和它们的定义。我已经编写了一个程序,从该文件中提取每行的第一个字,并根据用户输入的字符串进行检查:

void checkWord(string input)
{

    std::ifstream inFile;
    inFile.open("Oxford.txt");
    if (inFile.is_open())
    {
        string line; //there is a "using std::string" in another file
        while (getline(inFile, line))
        {
            //read the first word from each line
            std::istringstream iss(line);
            string word;
            iss >> word;
            //make sure the strings being compared are the same case
            std::transform(word.begin(), word.end(), word.begin(), ::tolower);
            std::transform(input.begin(), input.end(), input.begin(), ::tolower);
            if (word == input)
            {
                //Do a thing with word
            }
        }
        inFile.close();
        return "End of file";
    }
    else
    {
        return "Unable to open file";
    }

}
但是如果我检查的不仅仅是一个句子,那么处理它所需的时间就会变得明显。我考虑了几种缩短这段时间的方法:

  • 为字母表中的每个字母创建一个.txt文件(很容易做到,但从长远来看并不是一个真正的解决方案)
  • 使用unordered_set比较字符串(如所讨论的)唯一的问题可能是从文本文件中初始创建这些映射
  • 使用其他数据结构来比较字符串?(如std::map)
鉴于数据已经“排序”,我应该采用什么样的数据结构或方法来(如果可能的话)降低时间复杂度?另外,我用来比较字符串的函数有什么问题吗?(例如,string::compare()会比“==”?)快吗?或者一个hashmap(
std::unsorted_map
)?你的线性搜索显然是一个蛮力解决方案!对于多次搜索,上述两种方法都具有显著的优越性

当然,只有在每次程序运行时都要多次使用这些数据时,这才有真正的帮助,而您在问题中没有指定这些数据。如果不是,那么加载、解析和存储所有数据只是为了执行一次查找然后退出并没有多大好处。至少,只要在成功的时候加入一个
break


您的意思是您的输入文件已排序。您可以通过文件搜索(非常便宜)和在每次迭代中捕捉到最近的换行符来大致确定文件中具有相同前导(比如)三个字符的所有单词的位置,从而拼凑出一个二进制搜索解决方案。但是,对于一千个条目来说,这可能是过分了。

与其将所有内容都存储在
.txt
文件中,不如将其存储在真实的数据库中

SQLite3对于简单任务来说是一个不错的选择,因为它是进程中的,而不需要外部服务器

对于一个非常简单的例子,C API和SQL语句应该非常容易学习

比如:

-- Only do this once, for setup, not each time you run your program.
sqlite> CREATE TABLE dictionary (word TEXT PRIMARY KEY);
sqlite> .import /usr/share/dict/words dictionary;
-- Do this every time you run your program.
sqlite> select count(*) from dictionary where word = 'a';
1
因此,有“简单”的修复,也有一些更复杂的修复

第一步是将所有不必要的东西移出搜索循环:小写
输入
一次,在循环之前,而不是每次-毕竟,它没有改变。如果可能的话,也将
Oxford.txt
小写,这样就不必为每一行都使用小写的
word

如果要多次搜索文件,多次读取文件肯定不是一个很好的解决方案——即使它第二次缓存在文件系统中

因此,将它读入某个容器,真正简单的方法是
std::vector
[同时将字符串小写]并在其上迭代。下一个改进是对向量进行排序,并使用二进制搜索(但您必须自己编写二进制搜索-这并不难)


一个稍微复杂一点的解决方案[但搜索速度更快]是使用
std::map wordlist
(但这也需要更多的空间),然后使用
auto pos=wordlist.find(输入);如果(pos!=wordlist.end()…找到单词…

您可以受益于使用前缀树,也称为数据结构,因为它适合拥有字典并经常在其中查找单词的用例

trie最简单的模型是一个树,其中每个节点都持有一个字母和一个标志,以指示当前字母是否是单词的结尾(此外,还有指向该单词的其他数据的指针)

包含字典的trie示例图片
aback abate bird bird borning black black blast

要搜索单词,请从词根开始,对于单词的每个字母,请跟随包含当前字母的节点(如果它不是当前节点的子节点,则停止)。搜索时间与查找单词长度成比例,而不是与词典的大小成比例


trie还可以让您轻松获取字母(词典)字典中的单词顺序:只需对其进行运算。

此外,根据字符串计算的哈希值可能会有所帮助。老实说,我对一般的数据结构非常陌生,因此,我不确定要研究哪一种结构?此外,在整个程序过程中,我可能会相当频繁地调用此函数,因此所花的时间越短,t他更好。我说我的文件已排序,是指单词从A到Z排列,所以我也会进行二进制搜索?(谢谢)@Lucas:同时查看它们?@LucasSaldyt如果只查找一次预程序运行数据结构将没有帮助,只有更有效的方法才能找到文件中的单词。@LucasSaldyt对于多次运行读入
std::unordered\u map
(除非出于任何原因需要对它们进行排序,否则请使用std::map)然后,看一下。<代码> STD::IfStase是很慢的,你可以考虑另一种选择。通过1000个单词搜索真的需要这么长的时间吗?一些真正简单的改进是在读取文件之前降低文件的大小,并且在函数的开始只对输入单词进行一次缩小。多次,将文件内容加载到内存中并搜索加载的列表,而不是多次读取文件。@MatsPeterson:看起来对我来说是个答案!!我不认为每次迭代都需要将
input
转换为小写。这可能不会带来任何改进,因为一个好的编译器可能会优化这一部分,但它可以只是为了让代码看起来更好看。而且,我相信与之相比,
is>>word
可能是一个相当昂贵的操作