Hash Table template implementation help

Please support our C++ advertiser: Intel Parallel Studio Home
Reply

Join Date: Feb 2007
Posts: 10
Reputation: zakula11 is an unknown quantity at this point 
Solved Threads: 0
zakula11 zakula11 is offline Offline
Newbie Poster

Hash Table template implementation help

 
0
  #1
Feb 27th, 2007
Hey. I kindof posted tihs before but it didnt have a good title. But, I had to implement the functions of a Hash Table template... I wasn't sure exactly how to do it, but I figured out a way to get it to work. I'm not positive if I did it correctly though (and I need to make sure it is because I need to use it again for another project). So if you could look at it and tell me if its right, that would be awesome
Also, I couldnt figure out how to code the 'iterator'.

Thanks

Here is what i got:





  1. //
  2. // CS251 Data Structures
  3. // Hash Table template
  4. //
  5. #include <assert.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. ///////////////////////////////////////////
  9. //
  10. // Class that defines a template for a hash table
  11. // The keys are of type const char * and the data
  12. // can be any type.
  13. //
  14. // Use like this:
  15. // HashTable hashTableInt<int>;
  16. //
  17. //
  18. ///////////////////////////////////////////
  19.  
  20. // Each hash entry stores a key, object pair
  21. template <typename Data>
  22. struct HashTableEntry {
  23. const char * _key;
  24. Data _data;
  25. HashTableEntry * _next;
  26. };
  27.  
  28. // This is a Hash table that maps string keys to objects of type Data
  29. template <typename Data>
  30. class HashTable {
  31. public:
  32. // Number of buckets
  33. enum { TableSize = 2039};
  34.  
  35. // Array of the hash buckets.
  36. HashTableEntry<Data> **_buckets;
  37.  
  38. // Obtain the hash code of a key
  39. int hash(const char * key);
  40.  
  41. public:
  42. HashTable();
  43. // Add a record to the hash table. Returns true if key already exists.
  44. // Substitute content if key already exists.
  45. bool insertItem( const char * key, Data data);
  46.  
  47.  
  48. // Find a key in the dictionary and place in "data" the corresponding record
  49. // Returns false if key is does not exist
  50. bool find( const char * key, Data * data);
  51. // Removes an element in the hash table. Return false if key does not exist.
  52. bool removeElement(const char * key);
  53. };
  54.  
  55. template <typename Data>
  56. int HashTable<Data>::hash(const char * key)
  57. {
  58. // TODO: Compute the hash number from the key string
  59. int sum=0;
  60. int len = strlen(key);
  61. for(int i=0; i < len; i++)
  62. {
  63. sum = sum + key[i];
  64. }
  65. return sum % TableSize;
  66. }
  67.  
  68.  
  69. template <typename Data>
  70. HashTable<Data>::HashTable()
  71. {
  72. // TODO: Initialize the hash table
  73. _buckets = new HashTableEntry<Data> * [TableSize];
  74. for(int i=0; i < TableSize; i++)
  75. {
  76. _buckets[i] = NULL;
  77. }
  78. }
  79.  
  80. template <typename Data>
  81. bool HashTable<Data>::insertItem( const char * key, Data data)
  82. {
  83. // TODO: Insert a key,data pair inside the hash table.
  84. // Return true if the entry already exists or false if
  85. // it does not exist.
  86. int i = hash(key);
  87. HashTableEntry<Data> *e = _buckets[i];
  88.  
  89. while(e != NULL && strcmp(key, e->_key) != 0)
  90. {
  91. e = e->_next;
  92. }
  93.  
  94. if(e != NULL)
  95. {
  96. //key exists
  97. e->_data = data;
  98. return true;
  99. }
  100.  
  101. //key does not exist
  102. e = new HashTableEntry<Data>;
  103. assert(e != NULL);
  104.  
  105. e->_key = key;
  106. e->_data = data; //add entry to beg. of list
  107. e->_next = _buckets[i];
  108. _buckets[i] = e;
  109. return false;
  110. }
  111.  
  112.  
  113. template <typename Data>
  114. bool HashTable<Data>::find( const char * key, Data * data)
  115. {
  116. // TODO: Find the data associated to a key. The data is
  117. // stored in the *data passed as parameter.
  118. // Return true if the entry is found or false otherwise.
  119. int i = hash(key);
  120. HashTableEntry<Data> *e = _buckets[i];
  121.  
  122. while(e != NULL && strcmp(key, e->_key) != 0)
  123. {
  124. e = e->_next;
  125. }
  126.  
  127. //key is found
  128. if(e != NULL)
  129. {
  130. *data = e->_data;
  131. return true;
  132. }
  133.  
  134. //key was not found
  135. return false;
  136. }
  137.  
  138. template <typename Data>
  139. bool HashTable<Data>::removeElement(const char * key)
  140. {
  141. // TODO: Remove the element that has this key from the hash table.
  142. // Return true if the entry is found or false otherwise.
  143. int i = hash(key);
  144. HashTableEntry<Data> *eC = _buckets[i];
  145. HashTableEntry<Data> *eP = NULL;
  146.  
  147. while(eC != NULL && strcmp(key, eC->_key) != 0)
  148. {
  149. eP = eC;
  150. eC = eC->_next;
  151. }
  152.  
  153. //key is found
  154. if(eC != NULL)
  155. {
  156. if(eP != NULL)
  157. eP->_next = eC->_next;
  158. else
  159. _buckets[i] = eC->_next;
  160. return true;
  161. }
  162.  
  163. //key is not found
  164. return false;
  165. }
  166.  
  167.  
  168. /////////////////////////////////////
  169. //
  170. // Class used to iterate over the hash table
  171. //
  172. /////////////////////////////////////
  173. template <typename Data>
  174. class HashTableIterator {
  175. int _currentBucket; // Current bucket that is being iterated
  176. HashTableEntry<Data> *_currentEntry; // Current entry iterated
  177. HashTable<Data> * _hashTable; // Pointer to the hash table being iterated
  178. public:
  179. HashTableIterator(HashTable<Data> * hashTable);
  180. bool next(const char * & key, Data & data);
  181. };
  182.  
  183. template <typename Data>
  184. HashTableIterator<Data>::HashTableIterator(HashTable<Data> * hashTable)
  185. {
  186. // TODO: Initialize iterator. "hashTable" is the table to be iterated.
  187. _hashTable = hashTable;
  188. }
  189.  
  190. template <typename Data>
  191. bool HashTableIterator<Data>::next(const char * & key, Data & data)
  192. {
  193. // TODO: Returns the next element in the hash table.
  194. // The key and data values are stored in the references passed
  195. // as argument. It returns true if there are more entries or
  196. // false otherwise.
  197. return false;
  198. }
Reply With Quote Quick reply to this message  
Join Date: Jan 2007
Posts: 171
Reputation: Lazaro Claiborn is an unknown quantity at this point 
Solved Threads: 13
Lazaro Claiborn's Avatar
Lazaro Claiborn Lazaro Claiborn is offline Offline
Junior Poster

Re: Hash Table template implementation help

 
0
  #2
Feb 28th, 2007
Originally Posted by zakula11 View Post
  1. ... bool HashTableIterator<Data>::next(const char * & key, Data & data)
  2. {
  3. // TODO: Returns the next element in the hash table.
  4. // The key and data values are stored in the references passed
  5. // as argument. It returns true if there are more entries or
  6. // false otherwise.
  7. return false;
  8. }
Everything looks copacetic except for the above. The "next" member function might produce a compilation error because you specify a pointer and a referrence for parameter "key". But otherwise it looks good and it is very well formatted, kudo's. I usually use class instead of typename, but I haven't created any type of template in a while.

Good luck, LamaBot
Last edited by Lazaro Claiborn; Feb 28th, 2007 at 6:44 pm.
Reply With Quote Quick reply to this message  
Join Date: Feb 2007
Posts: 10
Reputation: zakula11 is an unknown quantity at this point 
Solved Threads: 0
zakula11 zakula11 is offline Offline
Newbie Poster

Re: Hash Table template implementation help

 
0
  #3
Feb 28th, 2007
Thanks. Any idea how to code the Iterator? I have not a clue :\
Reply With Quote Quick reply to this message  
Join Date: Jan 2007
Posts: 171
Reputation: Lazaro Claiborn is an unknown quantity at this point 
Solved Threads: 13
Lazaro Claiborn's Avatar
Lazaro Claiborn Lazaro Claiborn is offline Offline
Junior Poster

Re: Hash Table template implementation help

 
0
  #4
Feb 28th, 2007
Originally Posted by zakula11 View Post
Hey. I kindof posted tihs before but it didnt have a good title. But, I had to implement the functions of a Hash Table template... I wasn't sure exactly how to do it, but I figured out a way to get it to work. I'm not positive if I did it correctly though (and I need to make sure it is because I need to use it again for another project). So if you could look at it and tell me if its right, that would be awesome
Also, I couldnt figure out how to code the 'iterator'.

Thanks

Here is what i got:





  1. //
  2. // CS251 Data Structures
  3. // Hash Table template
  4. //
  5. #include <assert.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. ///////////////////////////////////////////
  9. //
  10. // Class that defines a template for a hash table
  11. // The keys are of type const char * and the data
  12. // can be any type.
  13. //
  14. // Use like this:
  15. // HashTable hashTableInt<int>;
  16. //
  17. //
  18. ///////////////////////////////////////////
  19.  
  20. // Each hash entry stores a key, object pair
  21. template <typename Data>
  22. struct HashTableEntry {
  23. const char * _key;
  24. Data _data;
  25. HashTableEntry * _next;
  26. };
  27.  
  28. // This is a Hash table that maps string keys to objects of type Data
  29. template <typename Data>
  30. class HashTable {
  31. public:
  32. // Number of buckets
  33. enum { TableSize = 2039};
  34.  
  35. // Array of the hash buckets.
  36. HashTableEntry<Data> **_buckets;
  37.  
  38. // Obtain the hash code of a key
  39. int hash(const char * key);
  40.  
  41. public:
  42. HashTable();
  43. // Add a record to the hash table. Returns true if key already exists.
  44. // Substitute content if key already exists.
  45. bool insertItem( const char * key, Data data);
  46.  
  47.  
  48. // Find a key in the dictionary and place in "data" the corresponding record
  49. // Returns false if key is does not exist
  50. bool find( const char * key, Data * data);
  51. // Removes an element in the hash table. Return false if key does not exist.
  52. bool removeElement(const char * key);
  53. };
  54.  
  55. template <typename Data>
  56. int HashTable<Data>::hash(const char * key)
  57. {
  58. // TODO: Compute the hash number from the key string
  59. int sum=0;
  60. int len = strlen(key);
  61. for(int i=0; i < len; i++)
  62. {
  63. sum = sum + key[i];
  64. }
  65. return sum % TableSize;
  66. }
  67.  
  68.  
  69. template <typename Data>
  70. HashTable<Data>::HashTable()
  71. {
  72. // TODO: Initialize the hash table
  73. _buckets = new HashTableEntry<Data> * [TableSize];
  74. for(int i=0; i < TableSize; i++)
  75. {
  76. _buckets[i] = NULL;
  77. }
  78. }
  79.  
  80. template <typename Data>
  81. bool HashTable<Data>::insertItem( const char * key, Data data)
  82. {
  83. // TODO: Insert a key,data pair inside the hash table.
  84. // Return true if the entry already exists or false if
  85. // it does not exist.
  86. int i = hash(key);
  87. HashTableEntry<Data> *e = _buckets[i];
  88.  
  89. while(e != NULL && strcmp(key, e->_key) != 0)
  90. {
  91. e = e->_next;
  92. }
  93.  
  94. if(e != NULL)
  95. {
  96. //key exists
  97. e->_data = data;
  98. return true;
  99. }
  100.  
  101. //key does not exist
  102. e = new HashTableEntry<Data>;
  103. assert(e != NULL);
  104.  
  105. e->_key = key;
  106. e->_data = data; //add entry to beg. of list
  107. e->_next = _buckets[i];
  108. _buckets[i] = e;
  109. return false;
  110. }
  111.  
  112.  
  113. template <typename Data>
  114. bool HashTable<Data>::find( const char * key, Data * data)
  115. {
  116. // TODO: Find the data associated to a key. The data is
  117. // stored in the *data passed as parameter.
  118. // Return true if the entry is found or false otherwise.
  119. int i = hash(key);
  120. HashTableEntry<Data> *e = _buckets[i];
  121.  
  122. while(e != NULL && strcmp(key, e->_key) != 0)
  123. {
  124. e = e->_next;
  125. }
  126.  
  127. //key is found
  128. if(e != NULL)
  129. {
  130. *data = e->_data;
  131. return true;
  132. }
  133.  
  134. //key was not found
  135. return false;
  136. }
  137.  
  138. template <typename Data>
  139. bool HashTable<Data>::removeElement(const char * key)
  140. {
  141. // TODO: Remove the element that has this key from the hash table.
  142. // Return true if the entry is found or false otherwise.
  143. int i = hash(key);
  144. HashTableEntry<Data> *eC = _buckets[i];
  145. HashTableEntry<Data> *eP = NULL;
  146.  
  147. while(eC != NULL && strcmp(key, eC->_key) != 0)
  148. {
  149. eP = eC;
  150. eC = eC->_next;
  151. }
  152.  
  153. //key is found
  154. if(eC != NULL)
  155. {
  156. if(eP != NULL)
  157. eP->_next = eC->_next;
  158. else
  159. _buckets[i] = eC->_next;
  160. return true;
  161. }
  162.  
  163. //key is not found
  164. return false;
  165. }
  166.  
  167.  
  168. /////////////////////////////////////
  169. //
  170. // Class used to iterate over the hash table
  171. //
  172. /////////////////////////////////////
  173. template <typename Data>
  174. class HashTableIterator {
  175. int _currentBucket; // Current bucket that is being iterated
  176. HashTableEntry<Data> *_currentEntry; // Current entry iterated
  177. HashTable<Data> * _hashTable; // Pointer to the hash table being iterated
  178. public:
  179. HashTableIterator(HashTable<Data> * hashTable);
  180. bool next(const char * & key, Data & data);
  181. };
  182.  
  183. template <typename Data>
  184. HashTableIterator<Data>::HashTableIterator(HashTable<Data> * hashTable)
  185. {
  186. // TODO: Initialize iterator. "hashTable" is the table to be iterated.
  187. _hashTable = hashTable;
  188. }
  189.  
  190. template <typename Data>
  191. bool HashTableIterator<Data>::next(const char * & key, Data & data)
  192. {
  193. // TODO: Returns the next element in the hash table.
  194. // The key and data values are stored in the references passed
  195. // as argument. It returns true if there are more entries or
  196. // false otherwise.
  197. return false;
  198. }
I'll have to get back at you about how to write the iterative portion. But I've noticed that you have the following code when declaring "_buckets":
  1. // Array of the hash buckets.
  2. HashTableEntry<Data> **_buckets;

When you initialize buckets in the HashTableEntry constructor, it returns an address to an array of type HashTableEntry. The above say's that buckets is going to hold an address, whose value is an address, whose value is the first address of a HashTableEntry object. But when you initialize it via "new" in the constructor, it returns an address, and places it in buckets which expects an address of pointer to type HashTableEntry. Also, when you're using new to create an array of size "HashTableSize" the generated code for the template class times HashTableSize is an expression. It seem like you'd want modify it to the following:

  1. // Array of the hash buckets.
  2. HashTableEntry<Data> *_buckets;
  3. ....
  4. // This is probably what you'd meant anyway
  5. buckets = new HashTableEntry<Data> [TableSize];

Anyway, if you've got any problem with the above let me know.

Good luck, LamaBot
Last edited by Lazaro Claiborn; Feb 28th, 2007 at 9:10 pm.
Reply With Quote Quick reply to this message  
Join Date: Feb 2007
Posts: 10
Reputation: zakula11 is an unknown quantity at this point 
Solved Threads: 0
zakula11 zakula11 is offline Offline
Newbie Poster

Re: Hash Table template implementation help

 
0
  #5
Feb 28th, 2007
I was given skeleton code for this project, and
  1. <LI class=li1> // Array of the hash buckets.
  2. HashTableEntry<Data> **_buckets;
was given to me already. I don't believe I was allowed to change it.
Now I'm working on another project , making a webcrawler, and I have most of it done, but the HashTable template is again holding me back. I need it to 1) map a URL to an index in an array, and 2) map a word to a list of URLs that contain that word.
Reply With Quote Quick reply to this message  
Join Date: Feb 2007
Posts: 539
Reputation: thekashyap will become famous soon enough thekashyap will become famous soon enough 
Solved Threads: 50
thekashyap's Avatar
thekashyap thekashyap is offline Offline
Posting Pro

Re: Hash Table template implementation help

 
0
  #6
Mar 1st, 2007
Looking at the declaration of HashTableEntry I assume your iterator is expected to be a ForwardIterator only (not Random, Bidirectional or Backward)
So here are few pointers for implementing a ForwardIterator.

A. Define the interface. For this look at the usecases.
Usecases:
  1. Get iterator to first and last element. (for for/while loop)
  2. Get iterator to nth element. (for find function)
  3. Support dereferencing (for getting to data).
  4. Support operator++. (for for/while loop)
B. Implementation changes required.
In HashTableIterator:
- Implement operator* (for point 3). Just return _currentEntry.
- Implement operator++. (for point 4): Just update _currentEntry with _currentEntry->next ;
- Implement a constructor that takes a HashTableEntry (for point 2). Update members based on HashTableEntry passed as argument.

In HashTable:
- Have a members (say m_first, m_end) of type HashTableIterator that represent first and last elements. For last element I remember (from some training) that HashTableIterator m_lastIter; should NOT be a valid iterator. In other words m_end does NOT point to the last element, but instead it's just an indicator that you've iterated thru the whole list. I forget the reason, but I guess it's just to simplify loop terminating condition. (for point 1).
- Update insertItem() so that it updates m_first on insertion if needed.
- Update the c'tor for the same thing.

Do get back if you need the code. But as always it would be nice for you to try first.

----------------------------
Just to comment on the existing implementation.
1. Inside insertItem().
  1. int i = hash(key);
  2. HashTableEntry<Data> *e = _buckets[i];
  3.  
  4. while(e != NULL && strcmp(key, e->_key) != 0)
  5. {
  6. e = e->_next;
  7. }
Isn't it that hash() ALWAYS returns same number for same key? If yes, why is the while loop present?
Instead of while loop shouldn't it be:
  1. if( NULL != e )
  2. {
  3. //Entry for this key already exists
  4. e->_data = data
  5. return true ;
  6. }
  7. else
  8. //key didn't exist do the needful...
Reason why I ask is if you are supposed to take care of collisions you need a lot more code than this. See this.
2. Inside insertItem(): I didn't get why is e->_next = _buckets[i]; done? For the purpose of implementing iterator it would be required that HashTableEntry::_next always contains a valid pointer. So it should be updated in such a way that it points to either next valid HashTableEntry or to m_end.
------------------------
Reply With Quote Quick reply to this message  
Join Date: Feb 2007
Posts: 539
Reputation: thekashyap will become famous soon enough thekashyap will become famous soon enough 
Solved Threads: 50
thekashyap's Avatar
thekashyap thekashyap is offline Offline
Posting Pro

Re: Hash Table template implementation help

 
0
  #7
Mar 1st, 2007
Sorry just saw that you have HashTableIterator::next(). You can either keep that or implement operator++. Both are one and the same from your code perspective, but just that clinets like me might prefer it++ then it = it->next().
Reply With Quote Quick reply to this message  
Join Date: Feb 2007
Posts: 10
Reputation: zakula11 is an unknown quantity at this point 
Solved Threads: 0
zakula11 zakula11 is offline Offline
Newbie Poster

Re: Hash Table template implementation help

 
0
  #8
Mar 1st, 2007
thekashyap, thanks for your reply. My biggest problem with the iterator was knowing where to start and end (I think... I'm also not exactly sure how to find the ones in the middle of their are empty indexes). Adding member variables to store the first and last elements may help me figure it out. I will try to code this after a few hours of sleep, haha.

In regards to your comment on my implementation of the hash() fuction.... each HashTableEntry in _buckets[] actually represents a linked list (at least thats the way I imagined it while I was writing the code, though I was also very confused)

So, yes it is true that hash() will always return the same number for the same key. However, it is also possible that the same number will be returned for different keys. When this is the case, it adds the entry to the linked list for that index in the hash table: e->_next;

Hence,
e->_next = _buckets[i]; is used in insertItem() because it is actually just adding the entry to the beginning of the current linked list. The next line after this sets _buckets[i] = e, resulting in the original list plus the new entry as the head of the list.
Reply With Quote Quick reply to this message  
Join Date: Feb 2007
Posts: 539
Reputation: thekashyap will become famous soon enough thekashyap will become famous soon enough 
Solved Threads: 50
thekashyap's Avatar
thekashyap thekashyap is offline Offline
Posting Pro

Re: Hash Table template implementation help

 
0
  #9
Mar 2nd, 2007
Aha now I understood. . You are indeed trying to take care of collisions. Then may be the link I gave in previous post would be good to see.

You mentioned that "each HashTableEntry in _buckets[] actually represents a linked list" => To ensure that the list is actually complete you must ensure what I said earlier:
"For the purpose of implementing iterator it would be required that HashTableEntry::_next always contains a valid pointer. So it should be updated in such a way that it points to either next valid HashTableEntry or to m_end."
When I ran your program and I see that _next is not set correctly for all HashTableEntry objects.

Now it may not be that easy to ensure that _next of all elements always point to appropriate HashTableEntry object (particularly when you're inserting in the middle, you need to go on both sides and find out not-null HashTableEntry objects and update _next for 2 objects).

It might be easier if you just maintain another array of integers that contains all indexes where a valid HashTableEntry object is present in _buckets. That way there won't be any need for _next. Add these members int _size, _filled_buckets[TableSize] ; to HashTable. In insertItem() just push hash value (i.e i) into this array. _filled_buckets[++_size] = i;. (you need to think how to implement removeItem() though).

Finally the most imp thing I forgot to mention, Iterator type should be a contained type in the container to which applies. I.e. HashTableInterator should be contained/declared inside HashTable. Once this is done the HashTableInterator::next() should just pickup the next index from _filled_buckets[] and update itself.
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:


Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC