【问题标题】:C++ Hash Table using chaining, remove method使用链接的 C++ 哈希表,删除方法
【发布时间】:2012-01-21 09:19:12
【问题描述】:

我正在使用链接在 C++ 中实现一个哈希表。代码构建没有错误,并且使用 insert 方法可以很好地构建表。但是,当我调用 remove 方法时,我收到以下错误:

HashTable.exe 中 0x00c53be9 处未处理的异常:0xC0000005:访问冲突读取位置 0x00000000。

哈希入口代码:

#include <string>
#include <vector>

template <class T>
class HashEntry
{
private:
    int key; //lookup key
    T value; //hash data
    HashEntry<T> *next;

public:
    HashEntry(int key, T value);
    HashEntry();
    int& getKey();
    T& getValue();
    void setValue(T value);
    HashEntry<T>* getNext();
    void setNext(HashEntry *next);
    bool operator == (HashEntry& rhs);
    bool operator != (HashEntry& rhs);
    HashEntry<T>& operator = (HashEntry& rhs);
};

template <class T> 
HashEntry<T>::HashEntry(int key, T value)
{
    this->key = key;
    this->value = value;
    this->next= nullptr;
}

template <class T>
HashEntry<T>::HashEntry()
{
    this->key = 0;
    this->next= nullptr;
}

template <class T>
int& HashEntry<T>::getKey()
{
    return key;
}

template <class T>
T& HashEntry<T>::getValue()
{
    return value;
}

template <class T>
void HashEntry<T>::setValue(T value)
{
    this->value = value;
}

template <class T>
HashEntry<T>* HashEntry<T>::getNext()
{
    return next;
}

template <class T>
void HashEntry<T>::setNext (HashEntry *next)
{
    this->next = next;
}

template <class T>
bool HashEntry<T>::operator == (HashEntry& rhs)
{
    return ((this->getKey() == rhs.getKey()) && (this->getValue() == rhs.getValue()));
}

template <class T>
bool HashEntry<T>::operator != (HashEntry& rhs)
{
    return ((this->getKey() != rhs.getKey()) && (this->getValue() != rhs.getValue()));
}

template <class T>
HashEntry<T>& HashEntry<T>::operator = (HashEntry& rhs)
{
    this->key = rhs.getKey();
    this->value = rhs.getValue();
    this->next = rhs.getNext();

    return *this;
}

哈希表代码:

template <class T>
class HashTable
{
private:
    std::vector<HashEntry<T>> table;
    static const int DEFAULT_TABLE_SIZE = 128;
    int TABLE_SIZE;


public:

    HashTable();
    void insert(int key, T value);
    void remove(int key);
    void get(int key);
    ~HashTable();
};

template <class T>
HashTable<T>::HashTable()
{
    TABLE_SIZE = DEFAULT_TABLE_SIZE;
    table.resize(TABLE_SIZE);
}

删除方法代码:

template <class T>
void HashTable<T>::remove(int key)
{
    int hashFunc = (key % TABLE_SIZE);

    if (table[hashFunc] != HashEntry<T>())
    {
        HashEntry<T> prevEntry = HashEntry<T>();
        HashEntry<T> entry = table[hashFunc];
        while (entry.getNext() != nullptr && entry.getKey() != key)
        {
            prevEntry = entry;
            entry = *entry.getNext();
        }
        if (entry.getKey() == key)
        {
            if (prevEntry == HashEntry<T>())
            {
                HashEntry<T> nextEntry = *entry.getNext(); //Where the exception is thrown
                entry = HashEntry<T>();
                table[hashFunc] = nextEntry;
            }

            else
            {
                HashEntry<T> *next = entry.getNext();
                entry = HashEntry<T>();
                prevEntry.setNext(next);
            }
        }
    }
}

【问题讨论】:

  • 如果您发布一个完整的可编译示例(可能在 ideone 等上,因此不会弄乱问题),包括测试代码,您将获得更好的答案。
  • 哦,没有什么比阅读 NULL 更能毁掉你的一天了。您的内存读取越界。
  • 我不知道这是否是您的实际问题,但 entry 是一个对象,而不是一个指针,因此它不需要 *entry.getNext() 中的取消引用星号。
  • 如果您可以使用一些 C++11 功能,您是否考虑过 boost 的实现(hash_mapunordered_map)或std::unordered_map,而不是重新发明轮子?

标签: c++ hashtable chaining


【解决方案1】:
while (entry.getNext() != nullptr && entry.getKey() != key)
{
    prevEntry = entry;
    entry = *entry.getNext();
}

几行之后,使用上面生成的条目:

HashEntry<T> nextEntry = *entry.getNext(); //Where the exception is thrown

while“使”entry.getNext() 成为nullptr。而且,稍后,您正试图取消引用它。并且取消引用 nullptr... 是一件坏事 (tm)。

顺便说一句,你为什么不对指针进行操作?我可能是错的,但是看你的代码,我感觉你想修改原始对象......而本地对象看起来像副本。

【讨论】:

  • 空值或等于所需值。如果为 nullptr,则在 if 语句 if (entry.getKey() == key) 上失败。
  • 我已将 nullptr 简单地更改为 NULL,但似乎无法修复错误。我尝试从 *entry.getNext() 中删除取消引用星号,但代码无法编译并引发错误:错误 2 错误 C2440: 'initializing' : cannot convert from 'HashEntry *' to 'HashEntry'
  • 第一:使用指针来操作对象。第二:取消引用nullptrNULL 等于取消引用0。不要这样做。
猜你喜欢
  • 1970-01-01
  • 2018-11-17
  • 2021-11-26
  • 2017-07-17
  • 1970-01-01
  • 2011-08-17
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
相关资源
最近更新 更多