【问题标题】:Improving insertion time of a hash table - C++改进哈希表的插入时间 - C++
【发布时间】:2025-12-19 01:25:13
【问题描述】:

我正在为一个类创建一个哈希表,并且我正在尝试提高插入速度。在我的实现中,我使用了链接。向量承载字符串列表。我必须从字典中插入超过 350,000 个单词到哈希表中(我大学计算机系的 /usr/share/dict/words 中的“单词”)。

这是我的哈希表。作业可能需要任何奇怪的命名约定(例如 MyDS):

#ifndef _MYDS_H
#define _MYDS_H

#include "MyHash.h"
#include <string>
#include <vector>
#include <list>
#include <iostream>

using namespace std;

class MyDS
{
public:
    MyDS()
    {
        max_size = 128;
        size = 0;
        nodes.resize(max_size);
    }

// destructor

// copy constructor

// assignment operator

    void push(const string& s)
        {
            unsigned long hash = MyHash()(s) % max_size;
            list<string> & hashList = nodes[hash];

            hashList.push_back(s);

            if (++size > nodes.size())
            {
                max_size *= 4;
                rehash();
            }
        }

bool search(const string& s)
{
    unsigned long hash = MyHash()(s) % max_size;
    list<string>::iterator it = nodes[hash].begin();

    for (int i = 0; i < nodes[hash].size(); i++)
    {
        if (*it == s)
        {
            return true;
        }
        *it++;
    }

    return false;
}
private:
    void rehash()
    {
        unsigned long hash;
        list<string>::iterator it;
        vector < list<string> > newNodes = nodes;
        newNodes.resize(max_size);

        for (int i = 0; i < nodes.size(); i++)
        {
            if (nodes[i].size() > 0)
            {
                it = nodes[i].begin();
                hash = MyHash()(*it) % max_size;
                newNodes[hash] = nodes[i];
            }
        }

        nodes = newNodes;
    }

    vector< list<string> > nodes;
    int max_size;
    int size;
};

#endif

我使用的散列函数是 djb2。我的搜索功能和插入似乎都非常快。重新散列需要很长时间。

如果有更好的方法来设置我的哈希表,请告诉我。我在做这个项目时使用的数据结构不受限制。

【问题讨论】:

  • 复制太多了。
  • 您可以将项目存储为散列(原始的、未修改的数字)和每个存储桶中的项目的对,这样就不需要重新散列了吗?只需重新读取存储的哈希值,根据新的最大大小对其进行修改并重新分配。
  • 碰撞或重新散列的次数取决于散列函数。您需要在快速函数和多次重新散列或更长的执行函数和更少的冲突之间进行选择。
  • 你确定每次推送都应该增加节点的一边吗?节点是每个哈希链
  • 您可以/应该重写 search 以减少噪音:bool search(const string &amp; s) { auto &amp; bucket = nodes[MyHash()(s) % max_size]; return bucket.end() != std::find(bucket.begin(), bucket.end(), s); }

标签: c++ hashtable


【解决方案1】:

停止复制所有这些字符串,只是为了在一分钟后看着它们燃烧。试试这个:

void rehash()
{
    std::vector<std::list<std::string>> newNodes(max_size);

    for (auto & bucket : nodes)
    {
        for (auto it = bucket.begin(); it != bucket.end(); )
        {
            std::list<std::string> & newBucket = newNodes[MyHash()(*it) % max_size];
            newBucket.splice(newBucket.end(), bucket, it++);
        }
    }

    nodes.swap(newNodes);
}   //    ^^^^^^^^^^^^^^

这也修复了实际上没有重新散列的损坏的“重新散列”。

【讨论】:

  • 我什至不知道 std::move,这真的很有用。谢谢!
  • @user1888527:实际上,这甚至不是最好的方法。我将其更改为直接重新拼接列表节点,从而为您节省 所有 分配。
  • 这比我原来的“方法”快很多。感谢您向我展示了一些我以前不知道的新事物!
【解决方案2】:
    if (nodes[i].size() > 0)
    {
        it = nodes[i].begin();
        hash = MyHash()(*it) % max_size;
        newNodes[hash] = nodes[i];
    }

我认为这些是不正确的。 nodes[i] 中的元素应该分布到更大表中的不同节点中。 因此,您需要重新计算每个元素的哈希值,而不仅仅是第一个元素。

【讨论】:

  • 好点!我有一个错误的思路导致了这一点,后来忽略了。
【解决方案3】:

您可能不想在节点数量等于大小时重新散列所有内容。附带说明一下,每当您将字符串添加到表中时,您都会增加大小,因此即使一个存储桶中有一个包含 128 个字符串的列表并且所有其他存储桶仍然是空的,您可以调整存储桶的数量,您确定这是逻辑吗你打算?我建议围绕 n 个桶的平方根进行分配,而不是重新散列。如果您使用了良好的哈希函数,则字符串到桶中的分布将相当均匀,并且查找时间根本不会受到太大影响。

【讨论】:

    【解决方案4】:

    “如果有更好的方法来设置我的哈希表,请告诉我。我在执行此项目时使用的数据结构不受限制。”

    在这种情况下,使用现有的 hashmap,例如 std::unordered_map 或 std::hash_map。我相信你在课堂上会不及格,但在现实生活中你会得到及格

    【讨论】:

    • 很有趣,但如果我的数据结构比那些更快,我会获得奖励积分!
    • 如果你能比标准容器更快地构建东西,我会感到震惊。希望你能做一个并排比较 - 那是额外的功劳
    • 不幸的是,并排比较已经是任务的一部分。不过,我会尽我最大的努力争取这额外的 5 分。