Dictionary.h

Go to the documentation of this file.
00001 /***************************************************************
00002  
00003  Mini Grand Challenge 2010
00004  Pennsylvania State University - Robotics Club
00005  Learn more at www.psurobotics.org
00006  Protected by the GNU General Public License
00007  
00008  This source file is developed and maintained by:
00009  + Jeremy Bridon jgbridon@gmail.com
00010  
00011  File: Dictionary.h
00012  Info: A simple template list hash-table (dictionary) implementation. Keys
00013  are string based. Linked-list implemented for collisions. The hash
00014  algorithm is based off of the jenkins-once-at-a-time hash. Read
00015  about it here: http://en.wikipedia.org/wiki/Hash_table Note that the
00016  "linked list" is simply a jagged array, not a single-linked-list.
00017  
00018 ***************************************************************/
00019 
00020 // Inclusion guard
00021 #ifndef __DICTIONARY_H_
00022 #define __DICTIONARY_H_
00023 
00024 // Includes
00025 #include "Utilities.h"
00026 #include "List.h"
00027 #include "Stack.h"
00028 
00030 template <typename Type> struct DictionaryNode
00031 {
00032         DictionaryNode(const char* givenKey, Type givenData)
00033         {
00034                 // Copy the given data and set the next pointer to null
00035                 key = new char[strlen(givenKey) + 1];
00036                 strcpy(key, givenKey);
00037                 data = givenData;
00038                 next = NULL;
00039         }
00040 
00041         ~DictionaryNode()
00042         {
00043                 delete[] key;
00044         }
00045 
00046         Type data;                                      
00047         char* key;                                      
00048         DictionaryNode<Type> *next;     
00049 };
00050 
00052 template <typename Type> class Dictionary
00053 {
00054 public:
00055 
00057         Dictionary(int size = DEFAULT_PAGE_SIZE, int RehashBound = DEFAULT_REHASH_BOUND)
00058                 : data(size)
00059         {
00060                 // Set the data list pointers to null
00061                 for(int i = 0; i < data.GetSize(); i++)
00062                         data[i] = NULL;
00063 
00064                 // Get the rehash count
00065                 rehashConflictCount = RehashBound;
00066                 elemCount = 0;
00067         }
00068 
00070         ~Dictionary()
00071         {
00072                 // Just call release, everything gets released through stack-popping
00073                 Release();
00074         }
00075         
00077         void Release()
00078         {
00079                 // For each linked-list
00080                 for(int i = 0; i < data.GetSize(); i++)
00081                 {
00082                         // For each element in the linked-list
00083                         DictionaryNode<Type> *current = data[i];
00084                         
00085                         while(current != NULL)
00086                         {
00087                                 DictionaryNode<Type> *next = current->next;
00088                                 delete current;
00089                                 current = next;
00090                         }
00091                 }
00092                 
00093                 // Set list size to zero
00094                 data.Resize(0);
00095         }
00096 
00098         void Insert(const char* key, Type obj)
00099         {
00100                 // Let us check that we do not already have this data, to prevent repeats
00101                 if(Find(key, obj))
00102                         return; // Already exists
00103 
00104                 // Get the key
00105                 unsigned int keyIndex = CreateKey(key);
00106 
00107                 // Create a DictionaryNode
00108                 DictionaryNode<Type> *newObj = new DictionaryNode<Type>(key, obj);
00109 
00110                 // Find the next valid spot in this chain (May 16: Optimized with pointer usage)
00111                 int depth = 0;
00112                 if(data[keyIndex % data.GetSize()] == NULL)
00113                         data[keyIndex % data.GetSize()] = newObj;
00114                 else
00115                 {
00116                         // Find a valid end of list to append to, but count our depth
00117                         DictionaryNode<Type> *current = data[keyIndex % data.GetSize()];
00118 
00119                         while(current->next != NULL)
00120                         {
00121                                 current = current->next;
00122                                 depth++;
00123                         }
00124 
00125                         // We found a valid pointer to place our new object
00126                         current->next = newObj;
00127                 }
00128 
00129                 // Grow the element counter
00130                 elemCount++;
00131 
00132                 // Check if we need to rehash
00133                 if(depth >= rehashConflictCount)
00134                         Rehash();
00135         }
00136 
00138         void Delete(const char* key)
00139         {
00140                 // Get the key
00141                 unsigned int keyIndex = CreateKey(key);
00142 
00143                 // Find the next valid spot in this chain
00144                 DictionaryNode<Type> *current = data[keyIndex % data.GetSize()];
00145                 DictionaryNode<Type> *prev = NULL;
00146 
00147                 while(current = NULL)
00148                 {
00149                         // Check for match
00150                         if(strcmp(current->key, key) == 0)
00151                         {
00152                                 // This is the parent of the list, update parent location
00153                                 if(prev == NULL)
00154                                 {
00155                                         DictionaryNode<Type> *next = current->next;
00156                                         delete current;
00157                                         data[keyIndex % data.GetSize()] = next;
00158                                 }
00159                                 // Remove current node and fix previous and next nodes
00160                                 else
00161                                 {
00162                                         prev->next = current->next;
00163                                         delete current;
00164                                 }
00165 
00166                                 // Remove the number from the list and return
00167                                 elemCount--;
00168                                 return;
00169                         }
00170 
00171                         // Set the previous nodes
00172                         prev = current;
00173                         current = current->next;
00174                 }
00175 
00176                 // Nothing found, thus nothing removed
00177         }
00178 
00180         bool Find(const char* key, Type &obj) // Ew at the "pass by reference" - Need to change this!
00181         {
00182                 // Get the key
00183                 unsigned int keyIndex = CreateKey(key);
00184 
00185                 // Find the next valid spot in this chain
00186                 DictionaryNode<Type> *current = data[keyIndex % data.GetSize()];
00187 
00188                 while(current != NULL)
00189                 {
00190                         // Check for a match
00191                         if(strcmp(current->key, key) == 0)
00192                         {
00193                                 // Copy over the data
00194                                 // This might be a design error without memcpy() due to complex structs that can't direct copy
00195                                 obj = current->data;
00196                                 return true;
00197                         }
00198 
00199                         // Look at the next current
00200                         current = current->next;
00201                 }
00202 
00203                 // No match, return false
00204                 return false;
00205         }
00206 
00208         int GetCount()
00209         {
00210                 return elemCount;
00211         }
00212 
00213 private:
00214 
00216         unsigned int CreateKey(const char* key)
00217         {
00218                 unsigned int hash = 0;
00219                 for(unsigned int i = 0; i < strlen(key); i++)
00220                 {
00221                         hash += key[i];
00222                         hash += (hash << 10);
00223                         hash ^= (hash >> 6);
00224                 }
00225                 hash += (hash << 3);
00226                 hash ^= (hash >> 11);
00227                 hash += (hash << 15);
00228 
00229                 // Return the hash index for the given data size
00230                 return (hash % data.GetSize());
00231         } 
00232 
00234         void Rehash()
00235         {
00236                 // Create a stack for all data
00237                 Stack<DictionaryNode<Type>*> stack(data.GetSize());
00238 
00239                 // Collect all data and push into the stack
00240                 for(int i = 0; i < data.GetSize(); i++)
00241                 {
00242                         // Find the next valid spot in this chain
00243                         DictionaryNode<Type> *current = data[i];
00244 
00245                         while(current != NULL)
00246                         {
00247                                 // Push current on stack and set current to next
00248                                 stack.Push(current);
00249                                 current = current->next;
00250                         }
00251                 }
00252 
00253                 // Grow the data list and clear it out (by a page)
00254                 data.Resize(data.GetSize() + DEFAULT_PAGE_SIZE);
00255                 for(int i = 0; i < data.GetSize(); i++)
00256                         data[i] = NULL;
00257 
00258                 // Pop back in the data
00259                 elemCount = 0;
00260                 while(stack.IsEmpty())
00261                 {
00262                         DictionaryNode<Type> *node;
00263                         node = stack.Pop();
00264                         Insert(node->key, node->data);
00265                 }
00266         }
00267 
00269         static const int DEFAULT_PAGE_SIZE = 16;
00270 
00272         static const int DEFAULT_REHASH_BOUND = 4;
00273 
00274         int elemCount;                                          
00275         int rehashConflictCount;                        
00276         
00277 public:
00278         
00279         // Note that we make this public so we can manually release all data!
00280         List<DictionaryNode<Type>*> data;       
00281 };
00282 
00283 #endif

Generated on Sun Feb 21 00:00:08 2010 for Penn State Robotics Club: Mini Grand Challenge 2010 by  doxygen 1.5.5