【问题标题】:Creating hashtable in C++ for string manipulation在 C++ 中创建哈希表以进行字符串操作
【发布时间】:2013-08-22 13:13:12
【问题描述】:

我正在尝试处理文章或任何段落的内容 [每个字符串]。首先,我将使用strtok() 转换成单词。

之后,我想将每个单词存储在哈希表中(因为我认为这是处理大数据的最佳方式)。在处理每个单词时,我想存储每个单词的出现。最后我想得到出现时间最长的单词。

unordered_map 存储带有键值的元素,并允许快速检索带有键的元素。这可能对我有用。

我不擅长C++,所以想请教一下。

  1. 将整个包含存储在char *ch ="content of article" 中是继续的好方法还是string::str?我只熟悉第一个。第二,我在处理函数时感觉很复杂。

  2. 将整个内容(字符串)存储到unordered_map(),然后我如何创建包含元素作为单词的哈希表,并且它会发生。然后我能得到出现次数最多的单词吗?

  3. 还有其他 C++ 函数可以帮助我做我想做的事吗?

【问题讨论】:

  • 请不要使用strtok,这是邪恶的。 Relevant link
  • 如果文本很大,你应该尝试找到解决方案,在解析之前不需要将整个文本读入内存。动态解析会提高效率。
  • @Borgleader:谢谢,但是您认为您链接的实现会按照我的要求与 strtok() 做同样的事情吗?
  • @AdamSangala:是的,但是从 pdf 或网络文档本身阅读对我来说是个问题。所以现在处理读取内存中的 frmo 文本!

标签: c++ hash hashtable


【解决方案1】:

您需要的数据结构似乎需要执行几个操作:按每个键的键(单词)和字符串值(计数)查找。但是你也希望能够打印出频繁的作品,这种情况下你需要按值排序。

没有一个标准容器可以开箱即用地处理这个问题。由于第一次操作会经常发生,而第二次只会发生一次,因此您应该选择最适合第一次操作的容器。

std::map 和 std::unordered_map 都可以。

尝试以下操作:

std::map<std::string, int>

unordered_map std::map<std::string, int>

要按频率顺序打印所有作品,您必须将其复制到另一个结构中,然后对其进行排序。或者它在一次操作中。您可以将所有内容复制到

std::map<int, std::string>

然后打印出来。

【讨论】:

  • 我不需要按顺序打印它们。我只需要出现次数最多的单词。如果超过 1,则全部。那么在这种情况下我需要对其进行排序吗?因为这需要额外的时间。
  • 您可以对最终地图进行 2 次遍历,一次确定最大计数,第二次打印所有罪魁祸首。这肯定会比排序更快。或者,您可以在解析时跟踪最大计数,避免其中一次通过。
【解决方案2】:

我想将每个单词存储在哈希表中(因为我认为这是处理大数据的最佳方式)。在处理每个单词时,我想存储每个单词的出现次数。

这里有一些伪 C++ 可以帮助您入门:

std::unordered_map<std::string, int> occurrences;
while (more_words_available)
{
    std::string word = fetch_next_word();
    ++occurrences[word];
}

如何打印 while 中每个单词的出现计数值?

你有 C++11 编译器吗?然后使用新的 foreach 循环:

for (auto p : occurrences)
{
    std::cout << p.first << " occurred " << p.second << " times.\n";
}

否则,使用带有迭代器的传统 for 循环:

for (std::unordered_map<std::string, int>::iterator it = occurrences.begin();
                                                    it != occurrences.end();
                                                    ++it)
{
    std::cout << it->first << " occurred " << it->second << " times.\n";
}

【讨论】:

  • 谢谢,我如何打印 while 中每个单词的出现计数值?
  • 谢谢,我认为这将解决我的问题。但是对于occurrence,我必须像typedef std::unordered_map&lt;std::string,int&gt; occurrences; 一样声明它。当我只给出字符串时,它会显示candidate expects two arguments。我必须处理应该自行获取计数值的文章内容,而这里我们必须手动提供。
【解决方案3】:
  1. 使用字符串总是更容易
  2. 单词可以用作键并计为值。从 unordered_map 中基于键的检索很快。获得最大数量的单词需要遍历整个地图。 您的问题是您需要 2 个索引。
  3. 考虑使用 Boost::MultiIndex 在容器中创建 2 个索引。

【讨论】:

    【解决方案4】:

    你不需要(也不想要)strtok。如果空白是 单词的分隔符,只需使用&gt;&gt; 读入字符串即可 做这个把戏;整个输入阶段将是:

    std::unordered_map<std::string, int> counts;
    std::string word;
    while ( source >> word ) {
        ++ counts[word];
    }
    

    根据要求,您可能想要执行以下操作 在计算之前将单词转换为小写,或 去掉最后的标点符号(这样wordWordWord. 都一样)。

    对于按计数排序的访问,最简单的方法是复制 将地图内容放入std::vector<std::pair<std::string, int>> 并对其进行排序。 (不要忘记你可以构造 来自两个迭代器的向量。所以这只是另外两行。)

    【讨论】:

    • @Karimkhan 在这种情况下,您可以使用std::getline,然后使用std::find_if(或std::find_first_of)将行分解为单词。对于非常复杂的情况,您甚至可以使用正则表达式。
    【解决方案5】:

    如果您的文章在文件 test.txt 中,那么您可以这样创建地图:

    #include<fstream>
    #include<map>
    #include<string>
    
    using namespace std;
    int main()
    {
        ifstream in_file("test.txt");
        map<string,int> words;
    
        string tword;
        while(in_file >> tword)  //line 12
            words[tword]++;
    }
    

    您还可以将整个内容存储在istringstream ss 中并使用它来代替上面的in_file

    while(ss >> twords)  //line 12
    

    【讨论】:

      猜你喜欢
      • 2019-07-29
      • 2011-11-29
      • 2013-04-07
      • 1970-01-01
      • 2015-10-11
      • 2017-06-23
      • 2013-08-22
      • 2011-04-28
      • 2019-04-01
      相关资源
      最近更新 更多