2014-11-23 62 views
0

节点的值,我应该创建一个存储用户名和密码,这是作为字符串存储的哈希映射。这个哈希映射是分开链接的。当增加一个值或搜索值,我应该使用哈希函数对返回一个整数,那么这将给我要斗我需要用一个函数的索引中的密钥。如果添加一些东西,我将它存储在列表的末尾。初始化在构造函数中的哈希表C++

所以散列图(在我心中)是这样的:

Bucket | List 
[0] -> nullptr 
[1] -> (key1/value1) -> (key2/value2) 
[2] -> (key3/value3) 

每个键/值组合在技术上是一个节点,其具有不可修改的结构,我的头文件中,就像这样:

struct Node 
{ 
    std::string key; 
    std::string value; 
    Node* next; 
}; 

尽管我的添加和搜索功能在技术上有效,但我想在构造函数中正确初始化我的哈希映射,以便我对而不是对未初始化的值进行比较。这是我现在的构造是如何:

HashMap::HashMap() 
    : hashTable{new Node*[initialBucketCount]}, amountOfBuckets{initialBucketCount}, sz{0} 
{ 
    for(int i = 0; i < amountOfBuckets; i++) { 
     hashTable[i] = nullptr; 
    } 
} 

的问题是,是,当我要比较的东西,就像在我的附加功能,我得到的valgrind一个错误,说我做一个条件跳转或移动未初始化的值。例如,在添加这样做:

Node* current = hashTable[tableIndex]; 
if(current == nullptr) 
    return false; 

会说if(current == nullptr)被引用未初始化值。

我将如何去正确的HashMap的构造函数初始化值?特别是,如果我想要做的事在我的列表的开头比较像nullptr值的函数,这样我可以决定,我需要把下一个节点在我的名单。

编辑:这里的一切都浓缩成一个文件。

/* HashMap.cpp */ 
namespace { 
    unsigned int hashFunc(const std::string& key) 
    { 
     unsigned int hashValue = 0; // what we end up returning 
     for(int i = 0; i < key.length(); i++) { // iterate through string 
      int letterIndex = key.at(i) - 96; // create an index for each ASCII char 
      hashValue = hashValue * 27 + letterIndex; 
     } 
     return hashValue; 
    } // end hashFunc 
} 
class HashMap 
{ 
public: 
    typedef std::function<unsigned int(const std::string&)> HashFunction; 
    static constexpr unsigned int initialBucketCount = 10; 

private: 
    struct Node 
    { 
     std::string key; 
     std::string value; 
     Node* next; 
    }; 
    HashFunction hasher; 
    Node** hashTable; 
    unsigned int amountOfBuckets; 
    unsigned int sz; 
public: 
    HashMap() 
    : hashTable{new Node*[initialBucketCount]}, amountOfBuckets{initialBucketCount}, sz{0} 
    { 
    for(int i = 0; i < amountOfBuckets; i++) { 
     hashTable[i] = nullptr; 
    } 
    } 
    HashMap(HashFunction hasher) 
    : hasher{hashFunc}, hashTable{new Node*[initialBucketCount]()}, amountOfBuckets{initialBucketCount}, sz{0} 
    { 
    for(int i = 0; i < amountOfBuckets; i++) { 
     hashTable[i] = nullptr; 
    } 
    } 
    HashMap(const HashMap& hm) 
    : hashTable{new Node*[hm.amountOfBuckets]}, amountOfBuckets{hm.amountOfBuckets}, sz{hm.sz} 
    { 
     for(unsigned int i = 0; i < sz; i++) { 
      hashTable[i] = hm.hashTable[i]; 
     } // end for 
    } 
    ~HashMap() 
    { 
    for(unsigned int i = 0; i < amountOfBuckets; i++) { 
     Node* bucketNode = hashTable[i]; // store each hashtable list in a bucket node 
     while(bucketNode != nullptr) { 
      Node* deleteCurrent = bucketNode; // set current to the bucket node (head) 
      bucketNode = bucketNode->next; // delete current is on the first node, update head to second node 
      delete deleteCurrent; 
     } // end while 
    } // end for 
    // once done, delete hash table 
    delete[] hashTable; 
    } // end destructor 

    void add(const std::string& key, const std::string& value) 
    { 
    unsigned int hashedValue = hashFunc(key); // get hash value (unmodified by buckets) 
    unsigned int tableIndex = getTableIndex(hashedValue); // get the table index 
    if(contains(key) == true) { // if key is already in the hashtable 
     return; // exit program 
    } else { // otherwise, key is not in the hash table 
     Node* head = hashTable[tableIndex]; // head of the hash table, represents 
     Node* current = head; // set current to first node 
     if(current == nullptr) { // no nodes yet 
      // nothing in bucket 
      current = new Node(); // construct single node 
      current->key = key; // set key (username) 
      current->value = value; // set value (password) 
      current->next = head; // add value to head of list 
      hashTable[tableIndex] = current; // update current to point to front of list 
      return; // exit 
     } else { 
      while(current->next != nullptr) { 
       current = current->next; // advance to next node 
      } // end while 
      // currently at node we want to insert key/value at 
      current = new Node(); 
      current->key = key; // set key(username) 
      current->value = value; // set value (pw) 
      current->next = nullptr; // set next to point to nullptr 
     } // end inner if-else (creates node) 
    } // end outer if-else 
    } // end add 
    bool contains(const std::string& key) const 
    { 
    unsigned int hashedValue = hashFunc(key); // hash the key given to get an index 
    unsigned int tableIndex = getTableIndex(hashedValue); // get the table index 
    Node* current = hashTable[tableIndex]; 
    if(current == nullptr) { // if there are no nodes at given index 
     return false; 
    } else { // there are some nodes in the hash table 
     while(current != nullptr && current->key != key) { 
      current = current->next; 
     } // end while 
     if(current == nullptr) { // we reached the end of our linked list 
      return false; // couldn't find a value 
     } else { // we found the key provided 
      return true; 
     } 
    } // end if-else 
    } 
    std::string value(const std::string& key) const 
    { 
     if(contains(key) == true) { // found match 
      unsigned int hashedValue = hashFunc(key); // hash the key given to get an index 
      unsigned int tableIndex = getTableIndex(hashedValue); // get the table index 
      Node* current = hashTable[tableIndex]; 
      while(current != nullptr && current->key != key) { 
       current = current->next; 
      } 
      return current->value; // return value after traversal 
     } else { 
      return ""; // no match, return empty string 
     } 
    } 
}; // end class 
/* main.cpp */ 

int main() 
{ 
    // initialize test 
    HashMap test1; 
    std::cout << "TEST 1 HASHMAP OBJECT CREATED" << std::endl; 
    // add some values 
    std::string key1 = "Alex"; 
    std::string value1 = "password1"; 
    std::string key2 = "Danielle"; 
    std::string value2 = "password2"; 
    std::cout << "strings have been created" << std::endl; 
    // add to hash map 
    test1.add(key1, value1); 
    test1.add(key2, value2); 
    std::cout << "Keys and values have been added to hash map" << std::endl; 
    // does key1 contain the word "hi"? no, should return false (0) 
    std::cout << "Hash map contains word hi?: " << test1.contains("hi") << std::endl; 
    // does key2 contain word "Danielle"? yes, should return true (1) 
    std::cout << "Hash map contains word Danielle?: " << test1.contains("Danielle") << std::endl; 
    // copy constructor test 
    HashMap test2{test1}; 
    test2.add("Chicken", "lizard1"); 
    std::cout << "Password for user Chicken: " << test2.value("Chicken") << std::endl; 
    HashMap test3 = test2; 
    // pw should stay lizard1 (doesn't work rn) 
    std::cout << "Password for user Chicken after copy: " << test3.value("Chicken") << std::endl; 
    // check to see if we get value 
    std::cout << "Password for user " << key1 << ": " << test1.value(key1) << std::endl; 
    std::cout << "Password for user " << key2 << ": " << test1.value(key2) << std::endl; 
    // should return empty string 
    std::cout << "Test of incorrect password for invalid user INVALID: " << test1.value("lol") << std::endl; 
    return 0; 
} 
+0

您的初始化看起来不错。没有看到MCVE,很难说valgrind的问题是什么。 (另外,我希望你不会在真实世界的程序中存储密码或编写自己的散列表)。 – 2014-11-23 04:31:09

+0

@ n.m。 MCVE是否只是valgrind的输出?在这种情况下,我可以添加一个编辑。在一个侧面说明,这只是一个类的作业:) – Alex 2014-11-23 04:34:43

+0

没有MCVE是完整的可重构的源代码,重现了这个问题。我可以复制,粘贴,编译,运行并查看您所看到的错误,而无需跳过箍环。 – 2014-11-23 04:38:29

回答

0

你写在你的默认评论构造函数

// initialize each node to nullptr from the array of buckets to nullptr 

,然后继续做别的东西完全。而另一件事是完全错误的。您将所有节点ptrs初始化为指向同一个节点。这意味着在销毁时你会多次删除同一个节点,并导致崩溃和烧毁。

而且解决这个问题的警告。

更新新版本的代码在修复了明显的错误之后,具有破坏的拷贝构造函数并且没有赋值运算符。

hashTable[i] = hm.hashTable[i]; 

将使两个散列表共享数据元素。你想要复制,而不是分享。你想复制所有的桶,而不是sz桶(你永远不会更新sz,但这是另一个问题)。

+0

那么,我将如何结束在每个桶索引初始化列表?我最初设置了hashTable [i] = nullptr,我原本认为它工作,但它确实没有。我需要在for循环的每次迭代中创建一些初始节点,并将它设置为等于索引i处的hashTable? – Alex 2014-11-23 07:17:06

+0

请确保您发布的代码是编译的。你缺少include指令,并且在任何地方都没有定义'getTableIndex'。在发布代码块之前,请自行编译并验证您是否获得了预期的输出。也请尽量不要在游戏中间更改代码,以免使答案失效。在修复明显的错误之后,您的当前版本具有损坏的复制构造函数并且没有赋值运算符。 – 2014-11-23 07:56:05