【问题标题】:Create hashtable where each value is a vector of many values创建哈希表,其中每个值都是许多值的向量
【发布时间】:2018-05-24 14:01:58
【问题描述】:

我有以下 input.txt 文件,它实际上有大约 150k 个 ID。

id    element
 0    1
 0    3
 1    0
 1    1
 1    3
 2    2
 2    4
 3    4
 4    1

我想将 id 存储为键,并将值存储在一个向量中,该向量包含每个 id 的值。例如最后我想要一个看起来像这样的哈希表。

0 -> 1, 3
1 -> 0, 1, 3
2 -> 2, 4
3 -> 4
4 -> 1

这是我目前的代码:

#include<iostream>
#include<cstdlib>
#include<vector>
using namespace std;
const int TABLE_SIZE = 128;

class HashEntry
{
    public:
        int key;
        vector< int > values;
        HashEntry(int key, int value)
        {
            this->key = key;
            values.push_back(value);
        }
};

class HashMap
{
    private:
        HashEntry **table;
    public:
        HashMap()
        {
            table = new HashEntry * [TABLE_SIZE];
            for (int i = 0; i< TABLE_SIZE; i++)
            {
                table[i] = NULL;
            }
        }
        /*
         * Hash Function
         */
        int HashFunc(int key)
        {
            return key % TABLE_SIZE;
        }

    void Insert(int key, int value)
    {
            int hash = HashFunc(key);
            table[hash] = new HashEntry(key, value);
    }

    void Show(){

        for (int i=0;i<TABLE_SIZE;i++){
            if (table[i]!=NULL){
                cout << table[i]->key << " : ";
                for(int y = 0; y < table[i]->values.size(); y++) {
                    cout << table[i]->values[y];
                }
                cout << endl;
            }
        }
    }
};

int main()
{
    HashMap hash;
    int key, value;
    while (1)
    {
    cout<<"Enter element to be inserted: ";
    cin>>value;
    cout<<"Enter key at which element to be inserted: ";
    cin>>key;
    hash.Insert(key, value);
    hash.Show();
    }
    return 0;
}

在控制台中,它只显示我输入的最后一个元素,而不是所有值。我认为问题在于 HashEntry 对象每次都被初始化,并且它的成员每次都从头开始初始化。如何让 HashEntries 保持“静态”?

编辑: 这是我遵循 Davide Spataro 建议后的新代码。不幸的是,我不能使用 C++11,所以我对其进行了一些更改。现在出了什么问题?

void Insert(int key, int value)
    {
            int hash = HashFunc(key);
            //check if we already have an `HashEntry` for key
            HashEntry *p = find(key, table[hash]);
            // if yes simply push the value in that `HashEntry`
            if( p->key == -1 ){
                p->values.push_back(value);
                return;
            }
            else{
                //otherwise add an `HashEntry` to the hashtable for key and push a value in it.
                HashEntry *p = new HashEntry(key, value);
                p->values.push_back(value);
                table[hash] = p;
            }

    }

    HashEntry* find(int key, HashEntry *table)
    {
        for (int i=0;i<TABLE_SIZE;i++)
        {
            if (key == table[i].key)
                return &table[i];
            else return new HashEntry(-1,-1);
        }
    }

【问题讨论】:

  • 请注意,您的 HasMap 不遵循 rule of 3/5/0,如果您尝试(或意外)复制它,将导致未定义的行为。
  • 既然你显然不反对使用std::vector(你使用一个HashEntry:: values;)那么为什么不使用一个HashMap::table;呢?
  • 好吧,关于你的插入,你不应该将新值添加到 table[hash] 而不是为它创建一个新的 HashEntry 吗?
  • 你们能解释清楚一点吗? @Jorge.V 如果我这样做,那么我将在哪里初始化 HashEntry?
  • @FrançoisAndrieux 谢谢你的回答。这样做我会得到什么?

标签: c++ pointers vector data-structures hashtable


【解决方案1】:

问题主要出在你的Insert。每当您找到一个散列到特定值的键时,您都会覆盖可能已经存在的HashEntry,从而创建一个新的!这是错误的,也会导致内存泄漏。

您还需要处理碰撞。您的哈希表中只有 128 存储桶和 150k 个可能的键值。对于鸽子原则,对于相同的哈希值,您最终将拥有多个 HashEntry。您的代码需要处理这个问题。

以下内容应该足以作为起点。

 void Insert(int key, int value)
    {
            int hash = HashFunc(key);
            //check if we already have an `HashEntry` for key 
            auto p = find(key, table[hash]);
            // if yes simply push the value in that `HashEntry` 
            if( p != nullptr){
                p->values.push_back(value);
                return;
            }else{
               //otherwise add an `HashEntry` to the hashtable for key and push a value in it.
              auto p = new HashEntry(key, value);
              p->values.push_back(value);
              table[hash] = p;
            }

    }

当您管理原始指针时,还有其他问题,例如 cmets 中提到的rule 3/5/0。 (您需要在某个时候释放该内存,不是吗?)

【讨论】:

  • 我根据您的宝贵建议编辑了我的问题。可以查一下吗?
猜你喜欢
  • 1970-01-01
  • 2021-06-29
  • 1970-01-01
  • 2015-02-02
  • 2017-11-03
  • 2021-06-19
  • 2018-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多