1 / 26

Implementing Maps

Implementing Maps. Eric Roberts CS 106B May 6, 2009. map.size(). map.put(key, value) or map[key] = value;. Returns the number of key/value pairs in the map. Makes an association between key and value , discarding any existing one. map.isEmpty().

Download Presentation

Implementing Maps

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Implementing Maps Eric Roberts CS 106B May 6, 2009

  2. map.size() map.put(key, value) or map[key] = value; Returns the number of key/value pairs in the map. Makes an association between key and value, discarding any existing one. map.isEmpty() Returns true if the map is empty. map.get(key) or map[key] map.containsKey(key) Returns the most recent value associated with key. Returns true if there is a value associated with key. map.remove(key) map.clear() Removes key from the map along with its associated value, if any. Removes all key/value pairs from the map. Methods in the Map<x> Class

  3. 1. 2. 3. 4. Create a Map<string> containing all 50 key/value pairs. Read in the two-letter abbreviation to translate. Call get on the Map to find the state name. Print out the name of the state. • To implement this program in C++, you need to perform the following steps, which are illustrated on the following slide: An Illustrative Mapping Application • Suppose that you want to write a program that displays the name of a state given its two-letter postal abbreviation. • This program is an ideal application for the Map class because what you need is a map between two-letter codes and state names. Each two-letter code uniquely identifies a particular state and therefore serves as a key for a Map; the state names are the corresponding values.

  4. void InitStateMap(Map<String> & map) { map.put("AL", "Alabama"); map.put("AK", "Alaska"); map.put("AZ", "Arizona"); map.put("FL", "Florida"); map.put("GA", "Georgia"); map.put("HI", "Hawaii"); map.put("WI", "Wisconsin"); map.put("WY", "Wyoming"); } int main() { Map<String> stateMap; InitStateMap(stateMap); while (true) { cout << "Enter two-letter state abbreviation: "; string code = GetLine(); if (code == "") break; if (stateMap.containsKey(code)) { cout << code << " is " << stateMap.get(code) << endl; } else { cout << code << " is not a known state abbreviation" << endl; } } } . . . . . . map stateMap The PostalLookup Program int main() { Map<String> stateMap; InitStateMap(stateMap); while (true) { cout << "Enter two-letter state abbreviation: "; string code = GetLine(); if (code == "") break; if (stateMap.containsKey(code)) { cout << code << " is " << stateMap.get(code) << endl; } else { cout << code << " is not a known state abbreviation" << endl; } } } code stateMap VE WI HI PostalLookup AL=Alabama AK=Alaska HI Enter two-letter state abbreviation: AZ=Arizona HI is Hawaii . . . Enter two-letter state abbreviation: WI FL=Florida WI is Wisconsin GA=Georgia Enter two-letter state abbreviation: VE HI=Hawaii . . . VE is not a known state abbreviation WI=Wisconsin Enter two-letter state abbreviation: WY=Wyoming skip simulation

  5. 1. Linear search in parallel arrays. Keep the two-character codes in one arrayand the state names in a second, making sure that the index numbers of the code and its corresponding state name always match. Such structures are called parallel arrays. You can use linear search to find the two-letter code and then take the state name from that position in the other array. This strategy takes O(N) time. 2. Binary search in parallel arrays. If you keep the arrays sorted by the two-character code, you can use binary search to find the key. Using this strategy improves the performance to O(log N). 3. Table lookup in a grid. In this specific example, you could store the state names in a 26x26 Grid<string> in which the first and second indices correspond to the two letters in the code. Because you can now find any code in a single step, this strategy is O(1), although this performance comes at a cost in memory space. Implementation Strategies for Maps There are several strategies you might choose to implement the map operations get and put. Those strategies include:

  6. The Idea of Hashing • The third strategy on the preceding slide shows that one can make the get and put operations run very quickly, even to the point that the cost of finding a key is independent of the number of keys in the table. This O(1) performance is possible only if you know where to look for a particular key. • To get a sense of how you might achieve this goal in practice, it helps to think about how you find a word in a dictionary. You certainly don’t start at the beginning at look at every word, but you probably don’t use binary search either. Most dictionaries have thumb tabs that indicate where each letter appear. Words starting with A are in the A section, and so on. • The Map class uses a strategy called hashing, which is conceptually similar to the thumb tabs in a dictionary. The critical idea is that you can improve performance enormously if you use the key to figure out where to look.

  7. In general, clients of the Map class have no reason to know the actual value of the integer returned as a hash code for a key. The important things to remember are: 1. 2. 3. Every string has a hash code, even if you don’t know what it is. The hash code for any particular string is always the same. If two strings are equal (i.e., they contain the same characters), they have the same hash code. Hash Codes • To make it possible for the Map class to know where to look for a particular key string, the implementation defines a hash method that returns an integer associated with each key. As you will see in a subsequent slide, this hash code value tells the Map implementation where it should look for a particular key, dramatically reducing the search time.

  8. In practice, the array of buckets is smaller than the number of hash codes, making it necessary to convert the hash code into a bucket index, typically by executing a statement like int index = hash(key) % nBuckets; The Bucket Hashing Strategy • One common strategy for implementing a map is to use the hash code for each key to select an index into an array that will contain all the keys with that hash code. Each element of that array is conventionally called a bucket. • The value in each element of the bucket array cannot be a single key/value pair given the chance that different keys fall into the same bucket. Such situations are called collisions. • To take account of the possibility of collisions, each elements of the bucket array is usually a linked list of the keys that fall into that bucket, as shown in the simulation on the next slide.

  9. The rest of the keys are added similarly. MA MA SD MA NE MO MA HI AZ GA KS LA DE ID KS DE CO NV ME KY MD DE ID DE MT ID CT MT TX RI PA OR IA MO AR OK MO RI NE PA OR GA KY AR CO CT KY DE CO ME NC NV ID VT MT LA ID GA NJ AZ CO CT DE MS KY KS MD CT CO KY VA LA KS WI ID ME NH KS NV CO NJ CO NH MD DE AZ CO TN LA SC MN NY NJ MD NC WY CT PA AZ CT MN AZ ND GA NY AZ GA SC SC RI MN OH NY IA AR ND OR OK MS WV OH WA MN NY TX ND OH MN NY AZ IA MI OK NM UT IA AR OK ND IA AR AR IA OR IA NY MT AR AR OK MI OK WA TX TN RI MN PA NM ND PA OR IA AR MI OK OR MN OH Massachusetts Massachusetts Massachusetts South Dakota Nebraska Missouri Massachusetts Hawaii Idaho New York Missouri Minnesota Tennessee Idaho Minnesota New York Ohio New York Colorado Minnesota New York New York North Dakota Ohio North Dakota Colorado Colorado South Carolina Maryland Michigan Minnesota North Dakota Delaware Ohio South Carolina Tennessee Virginia Wyoming North Carolina New Jersey Montana Kansas Delaware Delaware Missouri Idaho Minnesota Minnesota Oklahoma Colorado Colorado Delaware Kansas Arkansas Vermont Colorado Utah North Carolina New Jersey Mississippi Delaware Kansas Idaho Montana New Mexico Idaho Idaho New Mexico New Jersey New York North Dakota Ohio South Carolina Minnesota Nebraska North Dakota Michigan Montana Kansas Colorado Delaware Maine Delaware Michigan Kansas Montana Colorado New Hampshire Georgia Washington Maine Iowa Iowa Oregon Arkansas Oregon Louisiana Arkansas Kentucky Arkansas Maryland Pennsylvania Connecticut Arizona Rhode Island Texas Arkansas Pennsylvania Louisiana Iowa West Virginia Rhode Island Oregon Oklahoma Kentucky Oklahoma Oklahoma Louisiana Maine Iowa Iowa Arkansas Arkansas Pennsylvania Kentucky Oklahoma Oklahoma Washington Georgia Mississippi Arkansas Kentucky Pennsylvania Rhode Island Texas Wisconsin Oklahoma New Hampshire Nevada Louisiana Iowa Oregon Pennsylvania Connecticut Rhode Island Arizona Arizona Georgia Oregon Kentucky Texas Nevada Iowa Nevada Arizona Georgia Arizona Connecticut Georgia Connecticut Maryland Arizona Connecticut Maryland Oregon Iowa Connecticut Arkansas Arizona null SD NE MO MA HI South Dakota Nebraska Missouri Massachusetts Hawaii null IN IN CA HI IL IN IN AK HI IL FL AK IL CA AK AK FL AK CA FL HI AK IL HI AK AK FL AL FL CA AL CA IL AL AL CA AL AK IL AL AL FL AL IL CA IL CA AK CA Florida Alaska Alabama Florida Illinois Illinois Alabama Alaska Illinois Illinois Florida Alabama Alaska Alaska Alabama Illinois Hawaii Hawaii Illinois California Hawaii Alaska Hawaii California Alabama Illinois California Indiana Indiana Alabama Florida Alaska Indiana California Alabama Indiana Alaska California California Alaska Alaska Florida Alaska Florida Illinois California California Alabama California null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null Simulating Bucket Hashing stateMap.put("AL", "Alabama") 0 stateMap.put("AK", "Alaska") stateMap.put("AZ", "Arizona") 1 hash("AL") 2091 hash("AK") 2090 hash("AZ") 2105 2 3 2090 % 7 4 2091 % 7 5 2105 % 7 5 4 The key "AL" therefore goes in bucket 5. The key "AK" therefore goes in bucket 4. The key "AZ" therefore goes in bucket 5. 5 6 Because bucket 5 already contains "AL", the "AZ" must be added to the chain. Suppose you call stateMap.get("HI") hash("HI") 2305 2305 % 7 2 The key "HI" must therefore be in bucket 2 and can be located by searching the chain. skip simulation

  10. Achieving O(1) Performance • The simulation on the previous side uses only seven buckets to emphasize what happens when collisions occur: the smaller the number of buckets, the more likely collisions become. • In practice, the real implementation of Map uses a much larger value for nBuckets to minimize the opportunity for collisions. If the number of buckets is considerably larger than the number of keys, most of the bucket chains will either be empty or contain exactly one key/value pair. • The ratio of the number of keys to the number of buckets is called the load factor of the map. Because a map achieves O(1) performance only if the load factor is small, the library implementation of Map automatically increases the number of buckets when the table becomes too full.

  11. The map.h Interface /* * File: map.h * ----------- * This interface file defines the Map class template, which is * a collection for efficiently storing key-value pairs. */ #ifndef _map_h #define _map_h #include "genlib.h" /* * Class: Map * ---------- * This interface exports the Map class template, which stores a * set of key-value pairs. The fundamental methods supported by the * map class are put(key, value), which enters a new key/value pair * and get(key), which returns the most recent binding for key. * For maximum generality, Map is supplied as a class template. * The keys are always of type string, but the value type is set * by the client. The client specializes the map to hold values * of a specific type, e.g. Map<int> or Map<studentT>, as needed. */

  12. template <typename ValueType> class Map { public: /* * Constructor: Map * Usage: Map<int> map; * -------------------- * The constructor initializes a new empty map. */ Map(); /* * Destructor: ~Map * Usage: (usually implicit) * ------------------------- * The destructor deallocates all heap storage associated with this map. */ ~Map(); The map.h Interface /* * File: map.h * ----------- * This interface file defines the Map class template, which is * a collection for efficiently storing key-value pairs. */ #ifndef _map_h #define _map_h #include "genlib.h" /* * Class: Map * ---------- * This interface exports the Map class template, which stores a * set of key-value pairs. The fundamental methods supported by the * map class are put(key, value), which enters a new key/value pair * and get(key), which returns the most recent binding for key. * For maximum generality, Map is supplied as a class template. * The keys are always of type string, but the value type is set * by the client. The client specializes the map to hold values * of a specific type, e.g. Map<int> or Map<studentT>, as needed. */

  13. /* * Method: put * Usage: map.put(key, value); * --------------------------- * This method associates key with value in this map. Any * previous value associated with key is replaced by this new * entry. */ void put(string key, ValueType value); /* * Method: get * Usage: value = map.get(key); * ---------------------------- * If key is found in this map, this method returns the * associated value. If key is not found, raises an error. The * containsKey method can be used to verify the presence * of a key in the map before attempting to get its value. */ ValueType get(string key); The map.h Interface template <typename ValueType> class Map { public: /* * Constructor: Map * Usage: Map<int> map; * -------------------- * The constructor initializes a new empty map. */ Map(); /* * Destructor: ~Map * Usage: (usually implicit) * ------------------------- * The destructor deallocates all heap storage associated with this map. */ ~Map();

  14. /* * Method: containsKey * Usage: if (map.containsKey(key)) . . . * -------------------------------------- * Returns true if there is an entry for key in this map, false otherwise. */ bool containsKey(string key); /* . . . */ int size(); /* . . . */ bool isEmpty(); /* . . . */ void remove(string key); /* . . . */ void clear(); The map.h Interface /* * Method: put * Usage: map.put(key, value); * --------------------------- * This method associates key with value in this map. Any * previous value associated with key is replaced by this new * entry. */ void put(string key, ValueType value); /* * Method: get * Usage: value = map.get(key); * ---------------------------- * If key is found in this map, this method returns the * associated value. If key is not found, raises an error. The * containsKey method can be used to verify the presence * of a key in the map before attempting to get its value. */ ValueType get(string key);

  15. /* * Deep copying support * -------------------- * To maintain the desired behavior for a map, copying one * map to another must copy the data in the original map. * This type of copy is called a "deep copy". Unfortunately, * the default behavior of C++ makes only a "shallow copy" in * which any pointer variables in the private data are simply * copied as addresses. To ensure that the Map class performs * the necessary deep copy, it is necessary to override the * behavior of two methods: * * 1. The assignment operator (written as operator= in C++) * 2. The copy constructor that initializes one map from another * * Even though these operations must be supported to guarantee * correct behavior, you should avoid making copies of maps * wherever possible. To do so, the usual strategy is to pass * maps by reference so that the map is shared rather than * copied. */ The map.h Interface /* * Method: containsKey * Usage: if (map.containsKey(key)) . . . * -------------------------------------- * Returns true if there is an entry for key in this map, false otherwise. */ bool containsKey(string key); /* . . . */ int size(); /* . . . */ bool isEmpty(); /* . . . */ void remove(string key); /* . . . */ void clear();

  16. const Map & operator=(const Map & rhs); Map(const Map & rhs); private: #include "mappriv.h" }; /* * The template feature of C++ works correctly only if the compiler * has access to both the interface and the implementation at the * same time. As a result, the compiler must see the code for * the implementation at this point, even though that code is * not something that the client needs to see in the interface. * Using the #include facility of the C++ preprocessor allows the * compiler to have access to the code without forcing the client * to wade through the details. */ #include "mapimpl.cpp" #endif The map.h Interface /* * Deep copying support * -------------------- * To maintain the desired behavior for a map, copying one * map to another must copy the data in the original map. * This type of copy is called a "deep copy". Unfortunately, * the default behavior of C++ makes only a "shallow copy" in * which any pointer variables in the private data are simply * copied as addresses. To ensure that the Map class performs * the necessary deep copy, it is necessary to override the * behavior of two methods: * * 1. The assignment operator (written as operator= in C++) * 2. The copy constructor that initializes one map from another * * Even though these operations must be supported to guarantee * correct behavior, you should avoid making copies of maps * wherever possible. To do so, the usual strategy is to pass * maps by reference so that the map is shared rather than * copied. */

  17. Hash Table mappriv.h File /* * File: mappriv.h * --------------- * This file contains the private section of the Map template class. */ /* Type for a linked list cell */ struct cellT { string key; ValueType value; cellT *link; }; /* Instance variables */ cellT **buckets; /* A dynamic array of the bucket pointers */ int nBuckets; /* Allocated size of the buckets array */ int nEntries; /* The number of entries in the map */ /* Private method prototypes */ int hash(string s); void deleteChain(cellT *chain); cellT *findCell(cellT *chain, string key); void copyInternalData(const Map & oldMap);

  18. The mapimpl.cpp Implementation /* * File: mapimpl.cpp * ------------------ * This file implements the map.h interface. Because of the * way C++ templates are defined, it must be included as part * of the map.h header file. */ #ifdef _map_h #include "genlib.h" /* * Implementation notes: Internal representation of the Map class * -------------------------------------------------------------- * In this implementation, the entries are stored in a structure called * a "hash table", which stores each key in a place in the table determined * by computing a "hash function" on the key. There are many strategies * for implementing the hash table idea; this implementation keeps an * array of "buckets", where each bucket is a linked list of elements that * share the same hash code. If two or more keys have the same hash code, * each of those keys will be on the same list. Ideally, however, the * number of such "collisions" will be small, so that all of the operations * can run in constant time. To achieve that goal, it is necessary to * expand the number of buckets when the lists start to fill up. That * operation, which is called "rehashing" is not implemented here and * is instead left as an exercise. */

  19. /* Constants */ const int INITIAL_SIZE = 101; /* * Implementation notes: Map constructor, destructor * ------------------------------------------------- * The constructor allocates the array of buckets and initializes * each bucket to the empty list; the destructor must free all memory. */ template <typename ValueType> Map<ValueType>::Map() { nBuckets = INITIAL_SIZE; buckets = new cellT *[nBuckets]; for (int i = 0; i < nBuckets; i++) { buckets[i] = NULL; } } template <typename ValueType> Map<ValueType>::~Map() { clear(); delete[] buckets; } The mapimpl.cpp Implementation /* * File: mapimpl.cpp * ------------------ * This file implements the map.h interface. Because of the * way C++ templates are defined, it must be included as part * of the map.h header file. */ #ifdef _map_h #include "genlib.h" /* * Implementation notes: Internal representation of the Map class * -------------------------------------------------------------- * In this implementation, the entries are stored in a structure called * a "hash table", which stores each key in a place in the table determined * by computing a "hash function" on the key. There are many strategies * for implementing the hash table idea; this implementation keeps an * array of "buckets", where each bucket is a linked list of elements that * share the same hash code. If two or more keys have the same hash code, * each of those keys will be on the same list. Ideally, however, the * number of such "collisions" will be small, so that all of the operations * can run in constant time. To achieve that goal, it is necessary to * expand the number of buckets when the lists start to fill up. That * operation, which is called "rehashing" is not implemented here and * is instead left as an exercise. */

  20. /* * Implementation notes: put * ------------------------- * This method first looks to see whether the key already * exists in the map by calling the findCell method. If one * exists, this method simply changes the value; if not, the * implementation adds a new cell to the beginning of the chain. */ template <typename ValueType> void Map<ValueType>::put(string key, ValueType value) { int index = hash(key) % nBuckets; cellT *cell = findCell(buckets[index], key); if (cell == NULL) { cell = new cellT; cell->key = key; cell->link = buckets[index]; buckets[index] = cell; nEntries++; } cell->value = value; } The mapimpl.cpp Implementation /* Constants */ const int INITIAL_SIZE = 101; /* * Implementation notes: Map constructor, destructor * ------------------------------------------------- * The constructor allocates the array of buckets and initializes * each bucket to the empty list; the destructor must free all memory. */ template <typename ValueType> Map<ValueType>::Map() { nBuckets = INITIAL_SIZE; buckets = new cellT *[nBuckets]; for (int i = 0; i < nBuckets; i++) { buckets[i] = NULL; } } template <typename ValueType> Map<ValueType>::~Map() { clear(); delete[] buckets; }

  21. /* * Implementation notes: get, containsKey * -------------------------------------- * Each of these methods uses findCell to do most of the work. */ template <typename ValueType> ValueType Map<ValueType>::get(string key) { cellT *cell = findCell(buckets[hash(key) % nBuckets], key); if (cell == NULL) { Error("Attempt to get value for key which is not contained in map."); } return cell->value; } template <typename ValueType> bool Map<ValueType>::containsKey(string key) { return findCell(buckets[hash(key) % nBuckets], key) != NULL; } The mapimpl.cpp Implementation /* * Implementation notes: put * ------------------------- * This method first looks to see whether the key already * exists in the map by calling the findCell method. If one * exists, this method simply changes the value; if not, the * implementation adds a new cell to the beginning of the chain. */ template <typename ValueType> void Map<ValueType>::put(string key, ValueType value) { int index = hash(key) % nBuckets; cellT *cell = findCell(buckets[index], key); if (cell == NULL) { cell = new cellT; cell->key = key; cell->link = buckets[index]; buckets[index] = cell; nEntries++; } cell->value = value; }

  22. /* * Implementation notes: size, isEmpty * ----------------------------------- * These methods can each be implemented in a single line * because the size is stored in the nEntries instance variable. */ template <typename ValueType> int Map<ValueType>::size() { return nEntries; } template <typename ValueType> bool Map<ValueType>::isEmpty() { return nEntries; } template <typename ValueType> void Map<ValueType>::clear() { for (int i = 0; i < nBuckets; i++) { deleteChain(buckets[i]); } nEntries = 0; } The mapimpl.cpp Implementation /* * Implementation notes: get, containsKey * -------------------------------------- * Each of these methods uses findCell to do most of the work. */ template <typename ValueType> ValueType Map<ValueType>::get(string key) { cellT *cell = findCell(buckets[hash(key) % nBuckets], key); if (cell == NULL) { Error("Attempt to get value for key which is not contained in map."); } return cell->value; } template <typename ValueType> bool Map<ValueType>::containsKey(string key) { return findCell(buckets[hash(key) % nBuckets], key) != NULL; }

  23. /* * Implementation notes: remove * ---------------------------- * The remove method cannot use the findCell method as it * stands because it needs a pointer to the previous entry. */ template <typename ValueType> void Map<ValueType>::remove(string key) { int index = hash(key) % nBuckets; cellT *prev = NULL; cellT *cp = buckets[index]; while (cp != NULL && cp->key != key) { prev = cp; cp = cp->link; } if (cp != NULL) { if (prev == NULL) { buckets[index] = cp->link; } else { prev->link = cp->link; } delete cp; nEntries--; } } The mapimpl.cpp Implementation /* * Implementation notes: size, isEmpty * ----------------------------------- * These methods can each be implemented in a single line * because the size is stored in the nEntries instance variable. */ template <typename ValueType> int Map<ValueType>::size() { return nEntries; } template <typename ValueType> bool Map<ValueType>::isEmpty() { return nEntries; } template <typename ValueType> void Map<ValueType>::clear() { for (int i = 0; i < nBuckets; i++) { deleteChain(buckets[i]); } nEntries = 0; }

  24. /* Private methods */ template <typename ValueType> int Map<ValueType>::hash(string s) { const long MULTIPLIER = -1664117991L; unsigned long hashcode = 0; for (int i = 0; i < s.length(); i++) { hashcode = hashcode * MULTIPLIER + s[i]; } return hashcode & ((unsigned) -1 >> 1); } template <typename ValueType> void Map<ValueType>::deleteChain(cellT *chain) { if (chain != NULL) { deleteChain(chain->link); delete chain; } } template <typename ValueType> typename Map<ValueType>::cellT *Map<ValueType>::findCell(cellT *chain, typename Map<ValueType>::cellT *Map<ValueType>::findCell(string key) { for (cellT *cp = chain; cp != NULL; cp = cp->link) { if (cp->key == key) return cp; } return NULL; } The mapimpl.cpp Implementation /* * Implementation notes: remove * ---------------------------- * The remove method cannot use the findCell method as it * stands because it needs a pointer to the previous entry. */ template <typename ValueType> void Map<ValueType>::remove(string key) { int index = hash(key) % nBuckets; cellT *prev = NULL; cellT *cp = buckets[index]; while (cp != NULL && cp->key != key) { prev = cp; cp = cp->link; } if (cp != NULL) { if (prev == NULL) { buckets[index] = cp->link; } else { prev->link = cp->link; } delete cp; nEntries--; } }

  25. /* Private methods */ template <typename ValueType> int Map<ValueType>::hash(string s) { const long MULTIPLIER = -1664117991L; unsigned long hashcode = 0; for (int i = 0; i < s.length(); i++) { hashcode = hashcode * MULTIPLIER + s[i]; } return hashcode & ((unsigned) -1 >> 1); } template <typename ValueType> void Map<ValueType>::deleteChain(cellT *chain) { if (chain != NULL) { deleteChain(chain->link); delete chain; } } template <typename ValueType> typename Map<ValueType>::cellT *Map<ValueType>::findCell(cellT *chain, typename Map<ValueType>::cellT *Map<ValueType>::findCell(string key) { for (cellT *cp = chain; cp != NULL; cp = cp->link) { if (cp->key == key) return cp; } return NULL; } The mapimpl.cpp Implementation /* * Implementation notes: remove * ---------------------------- * The remove method cannot use the findCell method as it * stands because it needs a pointer to the previous entry. */ template <typename ValueType> void Map<ValueType>::remove(string key) { int index = hash(key) % nBuckets; cellT *prev = NULL; cellT *cp = buckets[index]; while (cp != NULL && cp->key != key) { prev = cp; cp = cp->link; } if (cp != NULL) { if (prev == NULL) { buckets[index] = cp->link; } else { prev->link = cp->link; } delete cp; nEntries--; } }

  26. The End

More Related