Download presentation
Presentation is loading. Please wait.
Published byAlisha Norman Modified over 9 years ago
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.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.