Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 11 Hash Tables Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.

Similar presentations


Presentation on theme: "1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 11 Hash Tables Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall."— Presentation transcript:

1 1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 11 Hash Tables Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall

2 2 Hash Table ADT The hash table is a table of elements that have keys A hash function is used for locating a position in the table The table of elements is the set of data acted upon by the hash table operations

3 3 Hash Table ADT Operations insert, to insert an element into a table retrieve, to retrieve an element from the table remove, to remove an element from the table update, to update an element in the table an operation to empty out the hash table

4 4 Fast Search A hash table uses a function of the key value of an element to identify its location in an array. A search for an element can be done in  ( 1 ) time. The function of the key value is called a hash function.

5 5 Hash Functions The input into a hash function is a key value The output from a hash function is an index of an array (hash table) where the object containing the key is located Example of a hash function: h( k ) = k % 100

6 6 Example Using a Hash Function Suppose our hash function is: h( k ) = k % 100 We wish to search for the object containing key value 214 k is set to 214 in the hash function The result is 14 The object containing key value 214 is stored at index 14 of the array (hash table) The search is done in  ( 1 ) time

7 7 Inserting an Element An element is inserted into a hash table using the same hash function h( k ) = k % 100 To find where an element is to be inserted, use the hash function on its key If the key value is 214, the object is to be stored in index 14 of the array Insertion is done in  ( 1 ) time

8 8 Consider the Big Picture … If we have millions of key values, it may take a long time to search a regular array or a linked list for a specific part number (on average, we might compare 500,000 key values) Using a hash table, we simply have a function which provides us with the index of the array where the object containing the key is located

9 9 Collisions Consider the hash function –h( k ) = k % 100 A key value of 393 is used for an object, and the object is stored at index 93 Then a key value of 193 is used for a second object; the result of the hash function is 93, but index 93 is already occupied This is called a collision

10 10 How are Collisions Resolved? The most popular way to resolve collisions is by chaining Instead of having an array of objects, we have an array of linked lists, each node of which contains an object An element is still inserted by using the hash function -- the hash function provides an index of a linked list, and the element is inserted at the front of that (usually short) linked list When searching for an element, the hash function is used to get the correct linked list, then the linked list is searched for the key (still much faster than comparing 500,000 keys)

11 11 01234560123456 A hash table which is initially empty. Every element is a LinkedList object. Only the start pointer of the LinkedList object is shown, which is set to NULL. The hash function is: h( k ) = k % 7 Example Using Chaining

12 12 01234560123456 INSERT object with key 31 Example Using Chaining (cont.) The hash function is: h( k ) = k % 7

13 13 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 31 31 % 7 is 3 Example Using Chaining (cont.)

14 14 01234560123456 31 The hash function is: h( k ) = k % 7 INSERT object with key 31 31 % 7 is 3 Example Using Chaining (cont.)

15 15 01234560123456 Note: The whole object is stored but only the key value is shown The hash function is: h( k ) = k % 7 INSERT object with key 31 31 % 7 is 3 Example Using Chaining (cont.) 31

16 16 The hash function is: h( k ) = k % 7 Example Using Chaining (cont.) 31 01234560123456

17 17 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 9 Example Using Chaining (cont.) 31

18 18 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 9 9 % 7 is 2 Example Using Chaining (cont.) 31

19 19 01234560123456 9 The hash function is: h( k ) = k % 7 INSERT object with key 9 9 % 7 is 2 Example Using Chaining (cont.) 31

20 20 01234560123456 The hash function is: h( k ) = k % 7 Example Using Chaining (cont.) 9 31

21 21 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 36 Example Using Chaining (cont.) 9 31

22 22 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 36 36 % 7 is 1 Example Using Chaining (cont.) 9 31

23 23 01234560123456 36 The hash function is: h( k ) = k % 7 INSERT object with key 36 36 % 7 is 1 Example Using Chaining (cont.) 9 31

24 24 01234560123456 The hash function is: h( k ) = k % 7 Example Using Chaining (cont.) 36 9 31

25 25 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 42 Example Using Chaining (cont.) 36 9 31

26 26 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 42 42 % 7 is 0 Example Using Chaining (cont.) 36 9 31

27 27 Example Using Chaining (cont.) 01234560123456 42 The hash function is: h( k ) = k % 7 INSERT object with key 42 42 % 7 is 0 36 9 31

28 28 01234560123456 The hash function is: h( k ) = k % 7 Example Using Chaining (cont.) 42 36 9 31

29 29 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 46 Example Using Chaining (cont.) 42 36 9 31

30 30 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 46 46 % 7 is 4 Example Using Chaining (cont.) 42 36 9 31

31 01234560123456 46 The hash function is: h( k ) = k % 7 INSERT object with key 46 46 % 7 is 4 Example Using Chaining (cont.) 42 36 9 31

32 32 01234560123456 The hash function is: h( k ) = k % 7 Example Using Chaining (cont.) 46 42 36 9 31

33 33 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 20 Example Using Chaining (cont.) 46 42 36 9 31

34 34 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 20 20 % 7 is 6 Example Using Chaining (cont.) 46 42 36 9 31

35 35 01234560123456 20 The hash function is: h( k ) = k % 7 INSERT object with key 20 20 % 7 is 6 Example Using Chaining (cont.) 46 42 36 9 31

36 36 01234560123456 The hash function is: h( k ) = k % 7 Example Using Chaining (cont.) 20 46 42 36 9 31

37 37 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 2 Example Using Chaining (cont.) 20 46 42 36 9 31

38 38 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 2 2 % 7 is 2 Example Using Chaining (cont.) 20 46 42 36 9 31

39 39 01234560123456 COLLISION occurs… The hash function is: h( k ) = k % 7 INSERT object with key 2 2 % 7 is 2 Example Using Chaining (cont.) 20 46 42 36 9 31

40 40 01234560123456 But key 2 is just inserted in the linked list The hash function is: h( k ) = k % 7 INSERT object with key 2 2 % 7 is 2 Example Using Chaining (cont.) 20 46 42 36 9 31

41 41 01234560123456 The insert function of LinkedList inserts a new element at the BEGINNING of the list The hash function is: h( k ) = k % 7 INSERT object with key 2 2 % 7 is 2 Example Using Chaining (cont.) 20 46 42 36 9 31

42 42 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 2 2 % 7 is 2 Example Using Chaining (cont.) 20 46 42 36 9 31

43 43 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 2 2 % 7 is 2 Example Using Chaining (cont.) 20 46 42 36 9 31

44 44 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 2 2 % 7 is 2 Example Using Chaining (cont.) 20 46 42 36 9 31

45 45 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 2 2 % 7 is 2 Example Using Chaining (cont.) 20 46 42 36 9 31

46 46 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 2 2 % 7 is 2 Example Using Chaining (cont.) 20 46 42 36 9 31

47 47 01234560123456 9 The hash function is: h( k ) = k % 7 INSERT object with key 2 2 % 7 is 2 Example Using Chaining (cont.) 20 46 42 36 2 31

48 48 01234560123456 The hash function is: h( k ) = k % 7 Example Using Chaining (cont.) 9 20 46 42 36 2 31

49 49 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 24 Example Using Chaining (cont.) 9 20 46 42 36 2 31

50 50 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 24 24 % 7 is 3 Example Using Chaining (cont.) 9 20 46 42 36 2 31

51 51 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 24 24 % 7 is 3 Example Using Chaining (cont.) 9 20 46 42 36 2 31

52 52 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 24 24 % 7 is 3 Example Using Chaining (cont.) 9 20 46 42 36 2 31

53 53 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 24 24 % 7 is 3 Example Using Chaining (cont.) 9 20 46 42 36 2 31

54 54 01234560123456 The hash function is: h( k ) = k % 7 INSERT object with key 24 24 % 7 is 3 Example Using Chaining (cont.) 9 20 46 42 36 2 31

55 55 01234560123456 31 The hash function is: h( k ) = k % 7 INSERT object with key 24 24 % 7 is 3 Example Using Chaining (cont.) 9 20 46 42 36 2 24

56 56 01234560123456 The hash function is: h( k ) = k % 7 Example Using Chaining (cont.) 31 9 20 46 42 36 2 24

57 57 01234560123456 The hash function is: h( k ) = k % 7 **FIND** the object with key 9 Example Using Chaining (cont.) 31 9 20 46 42 36 2 24

58 58 01234560123456 The hash function is: h( k ) = k % 7 **FIND** the object with key 9 9 % 7 is 2 Example Using Chaining (cont.) 31 9 20 46 42 36 2 24

59 59 01234560123456 We search this linked list for the object with key 9 The hash function is: h( k ) = k % 7 **FIND** the object with key 9 9 % 7 is 2 Example Using Chaining (cont.) 31 9 20 46 42 36 2 24

60 60 01234560123456 Remember…the whole object is stored, only the key is shown The hash function is: h( k ) = k % 7 **FIND** the object with key 9 9 % 7 is 2 Example Using Chaining (cont.) 31 9 20 46 42 36 2 24

61 61 01234560123456 Does this object contain key 9? The hash function is: h( k ) = k % 7 **FIND** the object with key 9 9 % 7 is 2 Example Using Chaining (cont.) 31 9 20 46 42 36 2 24

62 62 01234560123456 The hash function is: h( k ) = k % 7 **FIND** the object with key 9 9 % 7 is 2 Example Using Chaining (cont.) Does this object contain key 9? No, so go on to the next object. 31 9 20 46 42 36 2 24

63 63 The hash function is: h( k ) = k % 7 **FIND** the object with key 9 9 % 7 is 2 Example Using Chaining (cont.) Does this object contain key 9? 31 9 20 46 42 36 2 24 01234560123456

64 64 01234560123456 The hash function is: h( k ) = k % 7 **FIND** the object with key 9 9 % 7 is 2 Example Using Chaining (cont.) Does this object contain key 9? YES, found it! Return the object. 31 9 20 46 42 36 2 24

65 65 Uniform Hashing When the elements are spread evenly (or near evenly) among the indexes of a hash table, it is called uniform hashing If elements are spread evenly, such that the number of elements at an index is less than some small constant, uniform hashing allows a search to be done in  ( 1 ) time The hash function largely determines whether or not we will have uniform hashing

66 66 Bad Hash Functions h( k ) = 5 is obviously a bad hash function h( k ) = k % 100 could be a bad hash function if there is meaning attached to parts of a key –Consider that the key might be an employee id –The last two digits may give the state of birth

67 67 Ideal Hash Function for Uniform Hashing The hash table size should be a prime number that is not too close to a power of 2 31 is a prime number but is too close to a power of 2 97 is a prime number not too close to a power of 2 A good hash function might be: h( k ) = k % 97

68 68 Hash Functions Can be Made for Keys that are Strings 1int sum = 0; 2for ( int i = 0; i < int( str.length( ) ); i++ ) 3sum += str[ i ]; 4hash_index = sum % 97;

69 69 Speed vs. Memory Conservation Speed comes from reducing the number of collisions In a search, if there are no collisions, the first element in the linked list in the one we want to find (fast) Therefore, the greatest speed comes about by making a hash table much larger than the number of keys (but there will still be an occasional collision)

70 70 Speed vs. Memory Conservation (cont.) Each empty LinkedList object in a hash table wastes 8 bytes of memory (4 bytes for the start pointer and 4 bytes for the current pointer) The best memory conservation comes from trying to reduce the number of empty LinkedList objects The hash table size would be made much smaller than the number of keys (there would still be an occasional empty linked list)

71 71 Hash Table Design Decide whether speed or memory conservation is more important (and how much more important) for the application Come up with a good table size which –Allows for the use of a good hash function –Strikes the appropriate balance between speed and memory conservation

72 72 Ideal Hash Tables Can we have a hash function which guarantees that there will be no collisions? Yes: h( k ) = k Each key k is unique; therefore, each index produced from h( k ) is unique Consider 300 employees that have a 4 digit id A hash table size of 10000 with the hash function above guarantees the best possible speed

73 73 Ideal Hash Tables (cont.) Should we use LinkedList objects if there are no collisions? Suppose each Employee object takes up 100 bytes An array size of 10000 Employee objects with only 300 used indexes will have 9700 unused indexes, each taking up 100 bytes Best to use LinkedList objects (in this case) – the 9700 unused indexes will only use 8 bytes each Additional space can be saved by not storing the employee id in the object (if no collisions)

74 74 Ideal Hash Tables (cont.) Can we have a hash table without any collisions and without any empty linked lists? Sometimes. Consider 300 employees with id’s from 0 to 299. We can make a hash table size of 300, and use h( k ) = k LinkedList objects wouldn’t be necessary and in fact, would waste space It would also not be necessary to store the employee id in the object

75 75 Implementing a Hash Table We’ll implement a HashTable with linked lists (chaining) –without chaining, a hash table can become full If the client has the ideal hash table mentioned on the previous slide, he/she would be better off to just use an Array for the hash table

76 76 Implementing a Hash Function We shouldn’t write the hash function The client should write the hash function that he/she would like to use Then, the client should pass the hash function that he/she wrote as a parameter into the constructor of the HashTable class This can be implemented with function pointers

77 77 Function Pointers A function pointer is a pointer that holds the address of a function The function can be called using the function pointer instead of the function name

78 78 Function Pointers (cont.) Example of a function pointer declaration: float (*funcptr) (string);

79 79 Function Pointers (cont.) Example of a function pointer declaration: float (*funcptr) (string); funcptr is the name of the pointer; the name can be chosen like any other pointer name

80 80 Function Pointers (cont.) Example of a function pointer declaration: float (*funcptr) (string); The parentheses are necessary.

81 81 Function Pointers (cont.) Example of a function pointer declaration: float (*funcptr) (string); The return type of the function that funcptr can point to is given here (in this case, the return type is a float)

82 82 Function Pointers (cont.) Example of a function pointer declaration: float (*funcptr) (string); The parameter list of a function that funcptr can point to is given here – in this case, there is only one parameter of string type.

83 83 Function Pointers (cont.) Example of a function pointer declaration: float (*funcptr) (string); What would a function pointer declaration look like if the function it can point to has a void return type and accepts two integer parameters?

84 84 Function Pointers (cont.) void (*fp) (int, int);

85 85 Function Pointers (cont.) void (*fp) (int, int); void foo( int a, int b ) { cout << “a is: “ << a << endl; cout << “b is: “ << b << endl; } A function that fp can point to

86 86 Assigning the Address of a Function to a Function Pointer void (*fp) (int, int); void foo( int a, int b ) { cout << “a is: “ << a << endl; cout << “b is: “ << b << endl; } fp = foo; The address of foo is assigned to fp like this

87 87 Calling a Function by Using a Function Pointer Once the address of foo has been assigned to fp, the foo function can be called using fp like this void (*fp) (int, int); void foo( int a, int b ) { cout << “a is: “ << a << endl; cout << “b is: “ << b << endl; } fp( 5, 10 );

88 88 Design of the HashTable Constructor Once the client designs the hash function, the client passes the name of the hash function, as a parameter into the HashTable constructor The HashTable constructor accepts the parameter using a function pointer in this parameter location The address of the function is saved to a function pointer in the private section Then, the hash table can call the hash function that the client made by using the function pointer

89 89 HashTable.h 1 #include "LinkedList.h" 2 #include "Array.h“ 3 4 template 5 class HashTable 6 { 7 public: 8HashTable( int (*hf)(const DataType &), int s ); 9bool insert( const DataType & newObject ); 10bool retrieve( DataType & retrieved ); 11bool remove( DataType & removed ); 12bool update( DataType & updateObject ); 13void makeEmpty( ); HashTable.h continued…

90 90 HashTable.h 14 private: 15Array > table; 16int (*hashfunc)(const DataType &); 17 }; 18 19 #include "HashTable.cpp" Space is necessary here

91 91 Clientele The LinkedList class is being used in the HashTable class, along with the Array class Note that when one writes a class the clientele extends beyond the main programmers who might use the class The clientele extends to people who write other classes

92 92 HashTable Constructor 1 template 2 HashTable ::HashTable( 3 int (*hf)(const DataType &), int s ) 4: table( s ) 5 { 6hashfunc = hf; 7 } This call to the Array constructor creates an Array of LinkedList’s of type DataType

93 93 HashTable Constructor (cont.) 1 template 2 HashTable ::HashTable( 3 int (*hf)(const DataType &), int s ) 4: table( s ) 5 { 6hashfunc = hf; 7 } The DataType for Array is LinkedList (DataType in Array is different than DataType in HashTable)

94 94 HashTable Constructor (cont.) 1 template 2 HashTable ::HashTable( 3 int (*hf)(const DataType &), int s ) 4: table( s ) 5 { 6hashfunc = hf; 7 } In the Array constructor, an Array of size s is made, having LinkedList elements – when this array is created, the LinkedList constructor is called for each element.

95 95 HashTable Constructor (cont.) 1 template 2 HashTable ::HashTable( 3 int (*hf)(const DataType &), int s ) 4: table( s ) 5 { 6hashfunc = hf; 7 }

96 96 insert 8 template 8 9 bool HashTable ::insert( 10 const DataType & newObject ) 11 { 12int location = hashfunc( newObject ); 13if ( location = table.length( ) ) 14return false; 15table[ location ].insert( newObject ); 16return true; 17 } Keep in mind that this is a LinkedList object.

97 97 retrieve 18 template 19 bool HashTable ::retrieve( 20 DataType & retrieved ) 21 { 22int location = hashfunc( retrieved ); 23if ( location = table.length( ) ) 24return false; 25if ( !table[ location ].retrieve( retrieved ) ) 26return false; 27return true; 28 }

98 98 remove 29 template 30 bool HashTable ::remove( 31 DataType & removed ) 32 { 33int location = hashfunc( removed ); 34if ( location = table.length( ) ) 35return false; 36if ( !table[ location ].remove( removed ) ) 37return false; 38return true; 39 }

99 99 update 40 template 41 bool HashTable ::update( 42 DataType & updateObject ) 43 { 44int location = hashfunc( updateObject ); 45if ( location = table.length( ) ) 46return false; 47if ( !table[location].find( updateObject ) ) 48return false; 49table[location].replace( updateObject ); 50return true; 51 }

100 100 makeEmpty 50 template 51 void HashTable ::makeEmpty( ) 52 { 53for ( int i = 0; i < table.length( ); i++ ) 54table[ i ].makeEmpty( ); 55 }

101 101 Using HashTable 1 #include 2 #include 3 #include "HashTable.h" 4 5 using namespace std; 6 7 struct MyStruct { 8string str; 9int num; 10bool operator ==( const MyStruct & r ) { return str == r.str; } 11 }; str will be the key

102 102 Using HashTable (cont.) 1 #include 2 #include 3 #include "HashTable.h" 4 5 using namespace std; 6 7 struct MyStruct { 8string str; 9int num; 10bool operator ==( const MyStruct & r ) { return str == r.str; } 11 }; It is necessary to overload the == operator for the LinkedList functions

103 103 Using HashTable (cont.) 1 #include 2 #include 3 #include "HashTable.h" 4 5 using namespace std; 6 7 struct MyStruct { 8string str; 9int num; 10bool operator ==( const MyStruct & r ) { return str == r.str; } 11 }; In the actual code, a comment is placed above HashTable, telling the client that this is needed and what is required.

104 104 Using HashTable (cont.) 12 const int SIZE1 = 97, SIZE2 = 199; 13 14 int hash1( const MyStruct & obj ); 15 int hash2( const MyStruct & obj ); 16 17 int main( ) 18 { 19HashTable ht1( hash1, SIZE1 ), 20ht2( hash2, SIZE2);

105 105 Using HashTable (cont.) 21MyStruct myobj; 22 23myobj.str = "elephant"; 24myobj.num = 25; 25ht1.insert( myobj ); 26 27myobj.str = "giraffe"; 28myobj.num = 50; 29ht2.insert( myobj ); … // other code using the hash tables …

106 106 Using HashTable (cont.) 30return 0; 31 } 32 33 int hash1( const MyStruct & obj ) 34 { 35int sum = 0; 36for ( int i = 0; i < 3 && i < int( obj.str.length( ) ); i++ ) 37sum += obj.str[ i ]; 38return sum % SIZE1; 39 }

107 107 A Hash Table is Like a List The hash table ADT description is very close to the list ADT description The only items missing from the hash table ADT description are: –an iterator –a function to determine when the “list” is empty –find, to determine whether an element is in the “list” –a current position If we had all of these, we would have a fast list (or an enhanced hash table)

108 108 Iterator Everything would be easy to implement for the hash table, except for the iterator The iterator is an important part of a “list”, so we would like it to be as fast as possible We can iterate through a collision list, but finding the next collision list to iterate through might not be so fast…

109 109 Iterator (cont.) table Large gap with empty linked lists......

110 110 Iterator (cont.) Instead, we can have a linked list run through the collision lists, so that the linked list contains every element Then, iterating through the linked list is simple and fast

111 111 Time Complexities for List ADT insert – we’ll insert at the head of the linked list –  ( 1 ) iterator – each step will be  ( 1 ) find – element is found by hashing, so it is  ( 1 ) for uniform hashing (the hash function and hash table are designed so that the length of the collision list is bounded by some small constant) retrieve – is  ( 1 ) for uniform hashing more…

112 112 Time Complexities for List ADT (cont.) replace – is  ( 1 ) using the current position an operation to determine whether or not the list is empty – is  ( 1 ), because we just test the linked list to see if it is empty an operation to empty out the list – is  ( n ), the best we can do, since each node must be freed remove – to make this last operation as fast as possible, consider using a doubly-linked list for the linked list…

113 113 Remove In Chapter 10, we’ve seen that a node in a doubly-linked list can be removed in  ( 1 ) time, given a pointer to it Using hashing, we obtain a collision list, which will have a pointer to the node we wish to remove

114 114 Doubly-Linked List ADT The description for the doubly-linked list ADT is the same as that for the list ADT We don’t consider implementation in the ADT description, and double links have to do with implementation The implementation of the doubly-linked list using the HashTable is also not a part of the ADT description

115 115 Avoiding Special Cases To avoid special cases, we’ll have a header node and a trailer node in the doubly-linked list Few data structures use arrays of doubly- linked lists – if such a use arises, we could create a doubly-linked list without header and trailer nodes to avoid wasting memory

116 116 An Example 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 The red line is the doubly-linked list

117 117 An Example (cont.) 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 Each node has three pointers (not just one).

118 118 An Example (cont.) 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 The elements were inserted in this order: 33, 65, 63, 31, 53, 22, 47, 99, 36, 70

119 119 An Example (cont.) 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 33, 65, 63, 31, 53, 22, 47, 99, 36, 70 – since each node is inserted at the beginning …

120 120 An Example (cont.) 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 33, 65, 63, 31, 53, 22, 47, 99, 36, 70 – you’ll see these nodes from trailer to header.

121 121 An Example (cont.) 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52

122 122 An Example (cont.) 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52 The hash function gives us index 8.

123 123 An Example (cont.) 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52 So 52 is inserted at the beginning of the collision list there…

124 124 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52 So 52 is inserted at the beginning of the collision list there…

125 125 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52 So 52 is inserted at the beginning of the collision list there.

126 126 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52 So 52 is inserted at the beginning of the collision list there. 52

127 127 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 The new node, 52, must also be inserted at the beginning of the doubly-linked list… 52

128 128 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 The new node, 52, must also be inserted at the beginning of the doubly-linked list… 52

129 129 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 The new node, 52, must also be inserted at the beginning of the doubly-linked list 52

130 130 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 REMOVE: 31 52

131 131 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 REMOVE: 31 The hash function gives us index 9, where we’ll find 31 52

132 132 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 REMOVE: 31 Node 53 contains the pointer to it… 52

133 133 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 so 31 can be removed from the doubly-linked list in  ( 1 ) time… 52

134 134 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 so 31 can be removed from the doubly-linked list in  ( 1 ) time 52

135 135 An Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 31 is also removed from the collision list using LinkedList remove… 52

136 136 An Example (cont.) 4722 99 33 3670 63 5365 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 31 is also removed from the collision list using LinkedList remove 52

137 137 Doubly-Linked List Order The order of the doubly-linked list can be maintained independently of the singly- linked list If we wanted a sorted doubly-linked list using the same insertion order of the elements, it would look like this…

138 138 Sorted Example 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11

139 139 Sorted Example (cont.) 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52

140 140 Sorted Example (cont.) 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52 The hash function gives us index 8.

141 141 Sorted Example (cont.) 4722 99 33 36706353 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52 So 52 is inserted at the beginning of the collision list there…

142 142 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52 So 52 is inserted at the beginning of the collision list there…

143 143 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52 So 52 is inserted at the beginning of the collision list there.

144 144 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 INSERT: 52 So 52 is inserted at the beginning of the collision list there. 52

145 145 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 52 must also be inserted in the doubly-linked list… 52

146 146 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 52 52 must also be inserted in the doubly-linked list.

147 147 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 52 52 must also be inserted in the doubly-linked list. However…

148 148 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 52 it would take  ( n ) time since its position in the doubly- linked list must be found

149 149 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 REMOVE: 31 52

150 150 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 REMOVE: 31 The hash function gives us index 9, where we’ll find 31 52

151 151 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 REMOVE: 31 In  ( 1 ) time, it is removed from the doubly-linked list… 52

152 152 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 REMOVE: 31 In  ( 1 ) time, it is removed from the doubly-linked list 52

153 153 Sorted Example (cont.) 4722 99 33 3670 63 53 31 65 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 REMOVE: 31 In  ( 1 ) time, it is also removed from the collision list… 52

154 154 Sorted Example (cont.) 4722 99 33 3670 63 5365 0 1 2 3 4 5 6 7 8 9 10 trailer header hash function: h( k ) = k % 11 REMOVE: 31 In  ( 1 ) time, it is also removed from the collision list 52

155 155 Memory Considerations Each node has three pointers now: template struct Node { DataType info; Node *next; Node *dlnext; Node *dlback; }; For the collision list

156 156 Memory Considerations (cont.) Each node has three pointers now: template struct Node { DataType info; Node *next; Node *dlnext; Node *dlback; }; For the doubly-linked list

157 157 Memory Considerations (cont.) If there is only one node in the collision list, on average, then the LinkedList used for each element also has two pointers: start and current This gives us a total of 20 bytes of wasted memory per node (housekeeping)

158 158 Memory Considerations (cont.) If each element is 20 bytes, 50% of memory is wasted However, if each element is 980 bytes, only 2% of memory is wasted Element size is an important consideration

159 159 LinkedList Considerations In order to make the implementation easy, we’ll have to make some changes to the LinkedList class It will become a specialized “helper” class for the doubly-linked list

160 160 Changes to LinkedList change the name of the class from LinkedList to CollisionList modify the Node struct so it has the three pointers we need we need a function to retrieve the current pointer, called getcurrent instead of eliminating the current position when we insert a node, we will set the current position to the node we inserted

161 161 HashTable Class Considerations We’ll make some changes to the HashTable class, too It will, again, be a specialized “helper” class just for use in the doubly-linked list

162 162 HashTable Changes rename the HashTable class to DLHashTable, short for “Doubly-Linked Hash Table” keep the location, used throughout the class, as a private data member have a function getcurrent, which retrieves the current pointer of the CollisionList that was used in the last use of location; that is, return table[location].getcurrent( )

163 163 HashTable Changes We’ll also need some functions which are convenient for the copy constructor and deepCopy gethashfunc, which will return the hash function pointer sethashfunc, which will set a hash function pointer getsize, which will get the Array size of the hash table changeSize, which will change the Array size of the hash table

164 164 Returning a Function Pointer int (*gethashfunc( ) const)(const DataType &); This is the function prototype for gethashfunc, the function to return the hash function pointer.

165 165 Returning a Function Pointer (cont.) int (*gethashfunc( ) const)(const DataType &); This is the return type of the function – the return type is spread out instead of being at the beginning of the function heading, where it normally is.

166 166 Returning a Function Pointer (cont.) int (*gethashfunc( ) const)(const DataType &); The return type indicates we are returning a function pointer which can point to a function that passes in DataType by const reference and returns an integer (describing a hash function)

167 167 Returning a Function Pointer (cont.) int (*gethashfunc( ) const)(const DataType &); This is the name of the function that returns the function pointer – it has an empty parameter list in this case.

168 168 Returning a Function Pointer (cont.) int (*gethashfunc( ) const)(const DataType &); This const means that we are not going to change any of the data members in this function (it is the same use of const that you normally see at the end of an isEmpty function heading).

169 169 Returning a Function Pointer (cont.) template int (*DLHashTable ::gethashfunc( ) const) (const DataType &) { return hashfunc; } The function definition in the implementation file

170 170 DoublyLinkedList.h 1 #include "DLHashTable.h" 2 3 template 4 class DoublyLinkedList 5 { 6 public: 7DoublyLinkedList( 8 int (*hf)(const DataType &), int s ); 9DoublyLinkedList( 10 const DoublyLinkedList & aplist ); 11~DoublyLinkedList( ); 12DoublyLinkedList & operator =( 13 const DoublyLinkedList & rlist );

171 171 DoublyLinkedList.h (cont.) 14bool insert( const DataType & element ); 15bool first( DataType & listEl ); 16inline bool getNext( DataType & listEl ); 17bool last( DataType & listEl ); 18inline bool getPrevious( DataType & listEl ); 19bool find ( const DataType & element ); 20bool retrieve( DataType & element ); 21bool remove( DataType & element ); 22bool replace( const DataType & newElement ); 23bool isEmpty( ) const; 24void makeEmpty( ); another iterator

172 172 DoublyLinkedList.h (cont.) 25 private: 26DLHashTable table; 27Node *current; 28Node headerNode; 29Node trailerNode; 30Node *header; 31Node *trailer; 32inline void deepCopy( 33 const DoublyLinkedList & original ); 34 }; 35 36 #include "DoublyLinkedList.cpp" These are static nodes (not made in the heap).

173 173 DoublyLinkedList.h (cont.) 25 private: 26DLHashTable table; 27Node *current; 28Node headerNode; 29Node trailerNode; 30Node *header; 31Node *trailer; 32inline void deepCopy( 33 const DoublyLinkedList & original ); 34 }; 35 36 #include "DoublyLinkedList.cpp" header will point to headerNode

174 174 DoublyLinkedList.h (cont.) 25 private: 26DLHashTable table; 27Node *current; 28Node headerNode; 29Node trailerNode; 30Node *header; 31Node *trailer; 32inline void deepCopy( 33 const DoublyLinkedList & original ); 34 }; 35 36 #include "DoublyLinkedList.cpp" likewise, trailer will point to trailerNode

175 175 DoublyLinkedList.h (cont.) 25 private: 26DLHashTable table; 27Node *current; 28Node headerNode; 29Node trailerNode; 30Node *header; 31Node *trailer; 32inline void deepCopy( 33 const DoublyLinkedList & original ); 34 }; 35 36 #include "DoublyLinkedList.cpp" We don’t really need the header and trailer pointers, but without them the code may be confusing…

176 176 DoublyLinkedList.h (cont.) 25 private: 26DLHashTable table; 27Node *current; 28Node headerNode; 29Node trailerNode; 30Node *header; 31Node *trailer; 32inline void deepCopy( 33 const DoublyLinkedList & original ); 34 }; 35 36 #include "DoublyLinkedList.cpp" Without header, we would access the first data node with: headerNode.dlnext

177 177 DoublyLinkedList.h (cont.) 25 private: 26DLHashTable table; 27Node *current; 28Node headerNode; 29Node trailerNode; 30Node *header; 31Node *trailer; 32inline void deepCopy( 33 const DoublyLinkedList & original ); 34 }; 35 36 #include "DoublyLinkedList.cpp" WITH header, we would access the first data node with: header->dlnext

178 178 DoublyLinkedList.h (cont.) 25 private: 26DLHashTable table; 27Node *current; 28Node headerNode; 29Node trailerNode; 30Node *header; 31Node *trailer; 32inline void deepCopy( 33 const DoublyLinkedList & original ); 34 }; 35 36 #include "DoublyLinkedList.cpp" With this private section, do we really need a destructor, copy constructor, and overloaded assignment operator?

179 179 DoublyLinkedList.h (cont.) 25 private: 26DLHashTable table; 27Node *current; 28Node headerNode; 29Node trailerNode; 30Node *header; 31Node *trailer; 32inline void deepCopy( 33 const DoublyLinkedList & original ); 34 }; 35 36 #include "DoublyLinkedList.cpp" YES. There can be pointers to dynamic memory here (for example, header->next).

180 180 DoublyLinkedList.h (cont.) 25 private: 26DLHashTable table; 27Node *current; 28Node headerNode; 29Node trailerNode; 30Node *header; 31Node *trailer; 32inline void deepCopy( 33 const DoublyLinkedList & original ); 34 }; 35 36 #include "DoublyLinkedList.cpp" Sometimes pointers to dynamic memory are hidden.

181 181 Constructor 1 template 2 DoublyLinkedList ::DoublyLinkedList( 3 int (*hf)(const DataType &), int s ) 4 : table( hf, s ), header( &headerNode ), 5trailer( &trailerNode ) 6 { 7current = header->dlnext = trailer; 8trailer->dlback = header; 9 } When current is set to the trailer node, it means there is no current position

182 182 Copy Constructor 10 template 11 DoublyLinkedList ::DoublyLinkedList( 12 const DoublyLinkedList & aplist ) 13 : table( aplist.table.gethashfunc( ), aplist.table.getsize( ) ) 15 { 16deepCopy( aplist ); 17 } Calls the constructor for DLHashTable in the copy – passes in the hash function and size of the aplist hash table.

183 183 Destructor 18 template 19 DoublyLinkedList ::~DoublyLinkedList( ) 20 { 21makeEmpty( ); 22 }

184 184 Overloaded Assignment Operator 23 template 24 DoublyLinkedList & 25 DoublyLinkedList ::operator =( 26 const DoublyLinkedList & rlist ) 27 { 28if ( this == &rlist ) 29return *this; 30makeEmpty( ); 31deepCopy( rlist ); 32return *this; 33 }

185 185 insert 34 template 35 bool DoublyLinkedList ::insert( 36 const DataType & element ) 37 { 38if ( !table.insert( element ) ) 39return false; 40 41current = table.getcurrent( ); When insert in the CollisionList is (eventually) used, it now makes the inserted node the current node.

186 186 insert (cont.) 34 template 35 bool DoublyLinkedList ::insert( 36 const DataType & element ) 37 { 38if ( !table.insert( element ) ) 39return false; 40 41current = table.getcurrent( ); This function eventually calls getcurrent in the CollisionList, which returns the current pointer there…

187 187 insert (cont.) 34 template 35 bool DoublyLinkedList ::insert( 36 const DataType & element ) 37 { 38if ( !table.insert( element ) ) 39return false; 40 41current = table.getcurrent( ); So the address of the node that was just inserted is assigned to the (different) current pointer here

188 188 insert (cont.) 34 template 35 bool DoublyLinkedList ::insert( 36 const DataType & element ) 37 { 38if ( !table.insert( element ) ) 39return false; 40 41current = table.getcurrent( ); insert continued…

189 189 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } infodlbackdlnextnext In showing how insert works, we’ll use this convention for the parts of Node.

190 190 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start The current node has been inserted into the collision list (line 38 of insert)

191 191 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start However, it still needs to be placed into the doubly- linked list.

192 192 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start

193 193 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start

194 194 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start

195 195 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start

196 196 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start

197 197 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start

198 198 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start

199 199 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start

200 200 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start

201 201 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } doubly- linked list collision list current header start Now, current has been inserted into the doubly-linked list.

202 202 insert (cont.) 42current->dlnext = header->dlnext; 43current->dlback = header; 44header->dlnext = header->dlnext->dlback = current; 45current = trailer; 46 47return true; 48 } There won’t be a current position in the DoublyLinkedList after the insertion – the client is using the DoublyLinkedList and this is what the ADT describes.

203 203 first 49 template 50 bool DoublyLinkedList ::first( 51 DataType & listEl ) 52 { 53if ( header->dlnext == trailer ) 54return false; 55 56current = header->dlnext; 57listEl = current->info; 58return true; 59 }

204 204 getNext 60 template 61 inline bool DoublyLinkedList ::getNext( 62DataType & listEl ) 63 { 64if ( current->dlnext == trailer ) 65current = trailer; 66if ( current == trailer ) 67return false; 68 69current = current->dlnext; 70listEl = current->info; 71return true; 72 }

205 205 last 73 template 74 bool DoublyLinkedList ::last( 75DataType & listEl ) 76 { 77if ( header->dlnext == trailer ) 78return false; 79 80current = trailer->dlback; 81listEl = current->info; 82return true; 83 }

206 206 getPrevious 84 template 85 inline bool DoublyLinkedList ::getPrevious( 86DataType & listEl ) 87 { 88if ( current->dlback == header ) 89current = trailer; 90if ( current == trailer ) 91return false; 92 93current = current->dlback; 94listEl = current->info; 95return true; 96 }

207 207 find 97 template 98 bool DoublyLinkedList ::find( 99 const DataType & element ) 100 { 101DataType el = element; 102if ( table.retrieve( el ) ) { 103current = table.getcurrent( ); 104return true; 105} 106 107current = trailer; 108return false; 109 } If we pass in element here, retrieve will change the value of it…

208 208 find (cont.) 97 template 98 bool DoublyLinkedList ::find( 99 const DataType & element ) 100 { 101DataType el = element; 102if ( table.retrieve( el ) ) { 103current = table.getcurrent( ); 104return true; 105} 106 107current = trailer; 108return false; 109 } which will give us an error…in find, we are not supposed to retrieve

209 209 find (cont.) 97 template 98 bool DoublyLinkedList ::find( 99 const DataType & element ) 100 { 101DataType el = element; 102if ( table.retrieve( el ) ) { 103current = table.getcurrent( ); 104return true; 105} 106 107current = trailer; 108return false; 109 } So element is copied to el first, then passed into retreive.

210 210 find (cont.) 97 template 98 bool DoublyLinkedList ::find( 99 const DataType & element ) 100 { 101DataType el = element; 102if ( table.retrieve( el ) ) { 103current = table.getcurrent( ); 104return true; 105} 106 107current = trailer; 108return false; 109 } We could have passed by value here (instead of by const reference) to avoid this problem…

211 211 find (cont.) 97 template 98 bool DoublyLinkedList ::find( 99 const DataType & element ) 100 { 101DataType el = element; 102if ( table.retrieve( el ) ) { 103current = table.getcurrent( ); 104return true; 105} 106 107current = trailer; 108return false; 109 } but element copying (pass by value or here) can be avoided altogether by making a find function in DLHashTable (an exercise)

212 212 find (cont.) 97 template 98 bool DoublyLinkedList ::find( 99 const DataType & element ) 100 { 101DataType el = element; 102if ( table.retrieve( el ) ) { 103current = table.getcurrent( ); 104return true; 105} 106 107current = trailer; 108return false; 109 }

213 213 retrieve 110 template 111 bool DoublyLinkedList ::retrieve( 112 DataType & element ) 113 { 114if ( !find( element ) ) 115return false; 116 117element = current->info; 118return true; 119 }

214 214 remove 120 template 121 bool DoublyLinkedList ::remove( 122 DataType & element ) 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } sets element before it is removed

215 215 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( 122 DataType & element ) 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } also sets current to the node that element is in

216 216 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( 122 DataType & element ) 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } removes current node from doubly-linked list

217 217 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current

218 218 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current

219 219 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current

220 220 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current

221 221 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current

222 222 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current

223 223 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current trailer

224 224 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current trailer

225 225 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current trailer element is in the node current was pointing to

226 226 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current trailer element is in the node current was pointing to

227 227 remove (cont.) 120 template 121 bool DoublyLinkedList ::remove( DataType & element ) 122 123 { 124if ( !retrieve( element ) ) 125return false; 126current->dlback->dlnext = current->dlnext; 127current->dlnext->dlback = current->dlback; 128current = trailer; 129table.remove( element ); 130 131return true; 132 } doubly-linked list collision list current trailer

228 228 replace 133 template 134 bool DoublyLinkedList ::replace( 135 const DataType & newElement ) 136 { 137if ( current == trailer ) 138return false; 139current->info = newElement; 140return true; 141 }

229 229 isEmpty / makeEmpty 142 template 143 bool DoublyLinkedList ::isEmpty( ) const 144 { 145return header->dlnext == trailer; 146 } 147 148 template 149 void DoublyLinkedList ::makeEmpty( ) 150 { 151table.makeEmpty( ); 152current = header->dlnext = trailer; 153trailer->dlback = header; 154 }

230 230 deepCopy 155 template 156 inline void DoublyLinkedList ::deepCopy( 157 const DoublyLinkedList & original ) 158 { 159if ( original.table.getsize( ) != table.getsize( ) ) 160table.changeSize( original.table.getsize( ) ); 161table.sethashfunc( original.table.gethashfunc( ) ); 162header = &headerNode; 163trailer = &trailerNode; 164Node *save = header->dlnext = trailer; 165trailer->dlback = header; used later to set current

231 231 deepCopy (cont.) 166Node *originalptr = original.trailer->dlback; 167if ( (originalptr == original.header) || 168 !insert( originalptr->info ) ) 169return; start at the end of the original doubly-linked list

232 232 deepCopy (cont.) 166Node *originalptr = original.trailer->dlback; 167if ( (originalptr == original.header) || 168 !insert( originalptr->info ) ) 169return; If original doubly-linked list is empty, we want to return; we’ve already created an empty copy

233 233 deepCopy (cont.) 166Node *originalptr = original.trailer->dlback; 167if ( (originalptr == original.header) || 168 !insert( originalptr->info ) ) 169return; We may not be able to insert because of an error in the client’s hash function (detected in DLHashTable)

234 234 deepCopy (cont.) 166Node *originalptr = original.trailer->dlback; 167if ( (originalptr == original.header) || 168 !insert( originalptr->info ) ) 169return; By starting at the back of the original list and going forwards, we insert each node encountered into the front of the copy – ensuring a duplication.

235 235 deepCopy (cont.) 192while ( originalptr->dlback != original.header ) { 193originalptr = originalptr->dlback; 194if ( !insert( originalptr->info ) ) { 195makeEmpty( ); 196return; 197} 198if ( original.current == originalptr ) 199save = header->dlnext; 200} 201 202current = save; 203 } We want the current pointer in the original to correspond to the current pointer in the copy

236 236 deepCopy (cont.) 192while ( originalptr->dlback != original.header ) { 193originalptr = originalptr->dlback; 194if ( !insert( originalptr->info ) ) { 195makeEmpty( ); 196return; 197} 198if ( original.current == originalptr ) 199save = header->dlnext; 200} 201 202current = save; 203 } But we can’t set current in the copy yet – on each insert, the current pointer is changed.

237 237 deepCopy (cont.) 192while ( originalptr->dlback != original.header ) { 193originalptr = originalptr->dlback; 194if ( !insert( originalptr->info ) ) { 195makeEmpty( ); 196return; 197} 198if ( original.current == originalptr ) 199save = header->dlnext; 200} 201 202current = save; 203 } So we just save the current position of the copy in the save pointer.

238 238 deepCopy (cont.) 192while ( originalptr->dlback != original.header ) { 193originalptr = originalptr->dlback; 194if ( !insert( originalptr->info ) ) { 195makeEmpty( ); 196return; 197} 198if ( original.current == originalptr ) 199save = header->dlnext; 200} 201 202current = save; 203 } Whether save was set to trailer (before the while loop), or save was set in the while loop, this sets current correctly.


Download ppt "1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 11 Hash Tables Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall."

Similar presentations


Ads by Google