Вы находитесь на странице: 1из 238

C++ Classes and Data Structures

Jeffrey S. Childs

Chapter 11
Hash Tables
Jeffrey S. Childs
Clarion University of PA
© 2008, Prentice Hall
1
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

2
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

3
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.

4
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

5
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
6
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
7
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

8
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

9
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)

10
Example Using Chaining
0 A hash table which is initially
empty.
1
Every element is a LinkedList
2 object. Only the start pointer
of the LinkedList object is
3 shown, which is set to NULL.
4

5 The hash function is:


6 h( k ) = k % 7

11
Example Using Chaining
(cont.)
0

2
INSERT object
3 with key 31

5 The hash function is:


6 h( k ) = k % 7

12
Example Using Chaining
(cont.)
0

2
INSERT object
3 with key 31

4 31 % 7 is 3

5 The hash function is:


6 h( k ) = k % 7

13
Example Using Chaining
(cont.)
0

2
INSERT object
3 31 with key 31

4 31 % 7 is 3

5 The hash function is:


6 h( k ) = k % 7

14
Example Using Chaining
(cont.)
0
Note: The whole object is stored
1 but only the key value is shown

2
INSERT object
3 31 with key 31

4 31 % 7 is 3

5 The hash function is:


6 h( k ) = k % 7

15
Example Using Chaining
(cont.)
0

3 31

5 The hash function is:


6 h( k ) = k % 7

16
Example Using Chaining
(cont.)
0

2
INSERT object
3 31 with key 9

5 The hash function is:


6 h( k ) = k % 7

17
Example Using Chaining
(cont.)
0

2
INSERT object
3 31 with key 9

4 9 % 7 is 2

5 The hash function is:


6 h( k ) = k % 7

18
Example Using Chaining
(cont.)
0

2 9
INSERT object
3 31 with key 9

4 9 % 7 is 2

5 The hash function is:


6 h( k ) = k % 7

19
Example Using Chaining
(cont.)
0

2 9

3 31

5 The hash function is:


6 h( k ) = k % 7

20
Example Using Chaining
(cont.)
0

2 9
INSERT object
3 31 with key 36

5 The hash function is:


6 h( k ) = k % 7

21
Example Using Chaining
(cont.)
0

2 9
INSERT object
3 31 with key 36

4 36 % 7 is 1

5 The hash function is:


6 h( k ) = k % 7

22
Example Using Chaining
(cont.)
0

1 36

2 9
INSERT object
3 31 with key 36

4 36 % 7 is 1

5 The hash function is:


6 h( k ) = k % 7

23
Example Using Chaining
(cont.)
0

1 36

2 9

3 31

5 The hash function is:


6 h( k ) = k % 7

24
Example Using Chaining
(cont.)
0

1 36

2 9
INSERT object
3 31 with key 42

5 The hash function is:


6 h( k ) = k % 7

25
Example Using Chaining
(cont.)
0

1 36

2 9
INSERT object
3 31 with key 42

4 42 % 7 is 0

5 The hash function is:


6 h( k ) = k % 7

26
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 42

4 42 % 7 is 0

5 The hash function is:


6 h( k ) = k % 7

27
Example Using Chaining
(cont.)
0 42

1 36

2 9

3 31

5 The hash function is:


6 h( k ) = k % 7

28
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 46

5 The hash function is:


6 h( k ) = k % 7

29
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 46

4 46 % 7 is 4

5 The hash function is:


6 h( k ) = k % 7

30
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 46

4 46 46 % 7 is 4

5 The hash function is:


6 h( k ) = k % 7

31
Example Using Chaining
(cont.)
0 42

1 36

2 9

3 31

4 46

5 The hash function is:


6 h( k ) = k % 7

32
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 20

4 46

5 The hash function is:


6 h( k ) = k % 7

33
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 20

4 46 20 % 7 is 6

5 The hash function is:


6 h( k ) = k % 7

34
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 20

4 46 20 % 7 is 6

5 The hash function is:


6 20
h( k ) = k % 7

35
Example Using Chaining
(cont.)
0 42

1 36

2 9

3 31

4 46

5 The hash function is:


6 20
h( k ) = k % 7

36
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 2

4 46

5 The hash function is:


6 20
h( k ) = k % 7

37
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 2

4 46 2 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

38
Example Using Chaining
(cont.)
0 42
COLLISION occurs…
1 36

2 9
INSERT object
3 31 with key 2

4 46 2 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

39
Example Using Chaining
(cont.)
0 42
But key 2 is just inserted in
1 36 the linked list

2 9
INSERT object
3 31 with key 2

4 46 2 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

40
Example Using Chaining
(cont.)
0 42 The insert function of LinkedList
inserts a new element at the
1 36
BEGINNING of the list
2 9
INSERT object
3 31 with key 2

4 46 2 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

41
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 2

4 46 2 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

42
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 2

4 46 2 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

43
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 2

4 46 2 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

44
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 2

4 46 2 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

45
Example Using Chaining
(cont.)
0 42

1 36

2 9
INSERT object
3 31 with key 2

4 46 2 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

46
Example Using Chaining
(cont.)
0 42

1 36

2 2 9
INSERT object
3 31 with key 2

4 46 2 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

47
Example Using Chaining
(cont.)
0 42

1 36

2 2 9

3 31

4 46

5 The hash function is:


6 20
h( k ) = k % 7

48
Example Using Chaining
(cont.)
0 42

1 36

2 2 9
INSERT object
3 31 with key 24

4 46

5 The hash function is:


6 20
h( k ) = k % 7

49
Example Using Chaining
(cont.)
0 42

1 36

2 2 9
INSERT object
3 31 with key 24

4 46 24 % 7 is 3

5 The hash function is:


6 20
h( k ) = k % 7

50
Example Using Chaining
(cont.)
0 42

1 36

2 2 9
INSERT object
3 31 with key 24

4 46 24 % 7 is 3

5 The hash function is:


6 20
h( k ) = k % 7

51
Example Using Chaining
(cont.)
0 42

1 36

2 2 9
INSERT object
3 31 with key 24

4 46 24 % 7 is 3

5 The hash function is:


6 20
h( k ) = k % 7

52
Example Using Chaining
(cont.)
0 42

1 36

2 2 9
INSERT object
3 31 with key 24

4 46 24 % 7 is 3

5 The hash function is:


6 20
h( k ) = k % 7

53
Example Using Chaining
(cont.)
0 42

1 36

2 2 9
INSERT object
3 31 with key 24

4 46 24 % 7 is 3

5 The hash function is:


6 20
h( k ) = k % 7

54
Example Using Chaining
(cont.)
0 42

1 36

2 2 9
INSERT object
3 24 31 with key 24

4 46 24 % 7 is 3

5 The hash function is:


6 20
h( k ) = k % 7

55
Example Using Chaining
(cont.)
0 42

1 36

2 2 9

3 24 31

4 46

5 The hash function is:


6 20
h( k ) = k % 7

56
Example Using Chaining
(cont.)
0 42

1 36

2 2 9
**FIND** the
3 24 31 object with key 9

4 46

5 The hash function is:


6 20
h( k ) = k % 7

57
Example Using Chaining
(cont.)
0 42

1 36

2 2 9
**FIND** the
3 24 31 object with key 9

4 46 9 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

58
Example Using Chaining
(cont.)
0 42 We search this linked list for
the object with key 9
1 36

2 2 9
**FIND** the
3 24 31 object with key 9

4 46 9 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

59
Example Using Chaining
(cont.)
0 42 Remember…the whole object is
stored, only the key is shown
1 36

2 2 9
**FIND** the
3 24 31 object with key 9

4 46 9 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

60
Example Using Chaining
(cont.)
0 42 Does this object contain key 9?
1 36

2 2 9
**FIND** the
3 24 31 object with key 9

4 46 9 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

61
Example Using Chaining
(cont.)
0 42 Does this object contain key 9?
No, so go on to the next object.
1 36

2 2 9
**FIND** the
3 24 31 object with key 9

4 46 9 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

62
Example Using Chaining
(cont.)
0 42 Does this object contain key 9?
1 36

2 2 9
**FIND** the
3 24 31 object with key 9

4 46 9 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

63
Example Using Chaining
(cont.)
0 42 Does this object contain key 9?
YES, found it! Return the object.
1 36

2 2 9
**FIND** the
3 24 31 object with key 9

4 46 9 % 7 is 2

5 The hash function is:


6 20
h( k ) = k % 7

64
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

65
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

66
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

67
Hash Functions Can be
Made for Keys
that are Strings

1 int sum = 0;
2 for ( int i = 0; i < int( str.length( ) ); i++ )
3 sum += str[ i ];
4 hash_index = sum % 97;

68
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)
69
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)

70
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

71
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

72
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)

73
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

74
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

75
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
76
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

77
Function Pointers (cont.)
• Example of a function pointer declaration:

float (*funcptr) (string);

78
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

79
Function Pointers (cont.)
• Example of a function pointer declaration:

float (*funcptr) (string);

The parentheses are necessary.

80
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)

81
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.

82
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?

83
Function Pointers (cont.)

void (*fp) (int, int);

84
Function Pointers (cont.)

void (*fp) (int, int); A function that fp


can point to

void foo( int a, int b )


{
cout << “a is: “ << a << endl;
cout << “b is: “ << b << endl;
}

85
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;
}
The address of foo is
fp = foo; assigned to fp like this

86
Calling a Function
by Using a
Function Pointer
void (*fp) (int, int);

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

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

89
HashTable.h
Space is necessary here

14 private:
15 Array< LinkedList<DataType> > table;
16 int (*hashfunc)(const DataType &);
17 };
18
19 #include "HashTable.cpp"

90
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

91
HashTable Constructor

1 template <class DataType>


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

92
HashTable Constructor
(cont.)

1 template <class DataType>


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

93
HashTable Constructor
(cont.)

1 template <class DataType>


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

94
HashTable Constructor
(cont.)

1 template <class DataType>


2 HashTable<DataType>::HashTable(
3 int (*hf)(const DataType &), int s )
4 : table( s )
5 {
6 hashfunc = hf;
7 }

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

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

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

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

99
makeEmpty

50 template <class DataType>


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

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

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

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

103
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 {
19 HashTable<MyStruct> ht1( hash1, SIZE1 ),
20 ht2( hash2, SIZE2);

104
Using HashTable
(cont.)
21 MyStruct myobj;
22
23 myobj.str = "elephant";
24 myobj.num = 25;
25 ht1.insert( myobj );
26
27 myobj.str = "giraffe";
28 myobj.num = 50;
29 ht2.insert( myobj );

// other code using the hash tables

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

106
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)

107
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…

108
Iterator (cont.)
table

. Large gap
. with empty
.
linked lists

109
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

110
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…

111
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…

112
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

113
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

114
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

115
An Example
trailer hash function: The red line is the
h( k ) = k % 11 doubly-linked list

33

22 47 31
header
99 36 70 63 53 65

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

22 47 31
header
99 36 70 63 53 65

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

22 47 31
header
99 36 70 63 53 65

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

22 47 31
header
99 36 70 63 53 65

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

22 47 31
header
99 36 70 63 53 65

0 1 2 3 4 5 6 7 8 9 10
120
An Example (cont.)
trailer INSERT: 52
hash function:
h( k ) = k % 11
33

22 47 31
header
99 36 70 63 53 65

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

22 47 31
header
99 36 70 63 53 65

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

22 47 31
header
99 36 70 63 53 65

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

22 47 31
header 63
99 36 70 53 65

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

22 47 63 31
header
99 36 70 53 65

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

22 47 63 31
header
99 36 70 52 53 65

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

22 47 63 31
header
99 36 70 52 53 65

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

22 47 63 31
header
99 36 70 52 53 65

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

22 47 63 31
header
99 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
129
An Example (cont.)
trailer REMOVE: 31
hash function:
h( k ) = k % 11
33

22 47 63 31
header
99 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
130
An Example (cont.)
trailer REMOVE: 31
hash function:
The hash function gives us
h( k ) = k % 11 index 9, where we’ll find 31
33

22 47 63 31
header
99 36 70 52 53 65

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

22 47 63 31
header
99 36 70 52 53 65

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

22 47 63 31
header
99 36 70 52 53 65

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

22 47 63 31
header
99 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
134
An Example (cont.)
trailer 31 is also removed from the
hash function:
collision list using LinkedList
h( k ) = k % 11 remove…
33

22 47 63 31
header
99 36 70 52 53 65

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

22 47 63
header
99 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
136
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…

137
Sorted Example
hash function:
h( k ) = k % 11
33

22 47 31
header

99 trailer 36 70 63 53 65

0 1 2 3 4 5 6 7 8 9 10
138
Sorted Example (cont.)
hash function: INSERT: 52
h( k ) = k % 11
33

22 47 31
header

99 trailer 36 70 63 53 65

0 1 2 3 4 5 6 7 8 9 10
139
Sorted Example (cont.)
hash function: INSERT: 52
The hash function gives us
h( k ) = k % 11 index 8.
33

22 47 31
header

99 trailer 36 70 63 53 65

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

22 47 31
header

99 trailer 36 70 63 53 65

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

22 47 31
header
63
99 trailer 36 70 53 65

0 1 2 3 4 5 6 7 8 9 10
142
Sorted Example (cont.)
hash function: INSERT: 52 So 52 is inserted
at the beginning of the
h( k ) = k % 11 collision list there.
33

22 47 63 31
header

99 trailer 36 70 53 65

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

22 47 63 31
header

99 trailer 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
144
Sorted Example (cont.)
hash function: 52 must also be inserted in the
doubly-linked list…
h( k ) = k % 11
33

22 47 63 31
header

99 trailer 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
145
Sorted Example (cont.)
hash function: 52 must also be inserted in the
doubly-linked list.
h( k ) = k % 11
33

22 47 63 31
header

99 trailer 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
146
Sorted Example (cont.)
hash function: 52 must also be inserted in the
doubly-linked list. However…
h( k ) = k % 11
33

22 47 63 31
header

99 trailer 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
147
Sorted Example (cont.)
hash function: it would take ( n ) time since
its position in the doubly-
h( k ) = k % 11 linked list must be found
33

22 47 63 31
header

99 trailer 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
148
Sorted Example (cont.)
hash function: REMOVE: 31
h( k ) = k % 11
33

22 47 63 31
header

99 trailer 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
149
Sorted Example (cont.)
hash function: REMOVE: 31
The hash function gives us
h( k ) = k % 11 index 9, where we’ll find 31
33

22 47 63 31
header

99 trailer 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
150
Sorted Example (cont.)
hash function: REMOVE: 31
In ( 1 ) time, it is removed
h( k ) = k % 11 from the doubly-linked list…
33

22 47 63 31
header

99 trailer 36 70 52 53 65

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

22 47 63 31
header

99 trailer 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
152
Sorted Example (cont.)
hash function: REMOVE: 31
In ( 1 ) time, it is also
h( k ) = k % 11 removed from the collision
33 list…

22 47 63 31
header

99 trailer 36 70 52 53 65

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

22 47 63
header

99 trailer 36 70 52 53 65

0 1 2 3 4 5 6 7 8 9 10
154
Memory Considerations
• Each node has three pointers now:

template <class DataType>


struct Node {
DataType info;
Node<DataType> *next; For the collision list
Node<DataType> *dlnext;
Node<DataType> *dlback;
};

155
Memory Considerations
(cont.)
• Each node has three pointers now:

template <class DataType>


struct Node {
DataType info;
Node<DataType> *next;
Node<DataType> *dlnext;
For the doubly-linked
Node<DataType> *dlback; list
};

156
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)

157
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

158
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

159
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
160
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

161
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( )
162
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

163
Returning a
Function Pointer

int (*gethashfunc( ) const)(const DataType &);

This is the function prototype for gethashfunc, the


function to return the hash function pointer.

164
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.

165
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)

166
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.

167
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).

168
Returning a
Function Pointer
(cont.)
The function definition in the implementation file

template <class DataType>


int (*DLHashTable<DataType>::gethashfunc( ) const)
(const DataType &)
{
return hashfunc;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

182
Destructor

18 template <class DataType>


19 DoublyLinkedList<DataType>::~DoublyLinkedList( )
20 {
21 makeEmpty( );
22 }

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

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

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

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

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

insert continued…

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

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

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

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

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

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

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

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

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

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

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

Now, current has been


inserted into the
doubly-linked list. doubly-
linked list
201
insert (cont.)
42 current->dlnext = header->dlnext;
43 current->dlback = header;
44 header->dlnext = header->dlnext->dlback = current;
45 current = trailer;
46
47 return 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.

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

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

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

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

206
find
97 template <class DataType>
98 bool DoublyLinkedList<DataType>::find(
99 const DataType & element )
100 {
101 DataType el = element; If we pass in
102 if ( table.retrieve( el ) ) { element here,
103 current = table.getcurrent( ); retrieve will
104 return true; change the value
105 } of it…
106
107 current = trailer;
108 return false;
109 }
207
find (cont.)
97 template <class DataType>
98 bool DoublyLinkedList<DataType>::find(
99 const DataType & element )
100 {
101 DataType el = element; which will give
102 if ( table.retrieve( el ) ) { us an error…in
103 current = table.getcurrent( ); find, we are not
104 return true; supposed to
105 } retrieve
106
107 current = trailer;
108 return false;
109 }
208
find (cont.)
97 template <class DataType>
98 bool DoublyLinkedList<DataType>::find(
99 const DataType & element )
100 {
101 DataType el = element; So element is
102 if ( table.retrieve( el ) ) { copied to el first,
103 current = table.getcurrent( ); then passed into
104 return true; retreive.
105 }
106
107 current = trailer;
108 return false;
109 }
209
find (cont.)
97 template <class DataType>
98 bool DoublyLinkedList<DataType>::find(
99 const DataType & element )
100 {
101 DataType el = element; We could have
102 if ( table.retrieve( el ) ) { passed by value
103 current = table.getcurrent( ); here (instead of
104 return true; by const
105 } reference) to
106 avoid this
107 current = trailer; problem…
108 return false;
109 }
210
find (cont.)
97 template <class DataType>
98 bool DoublyLinkedList<DataType>::find(
99 const DataType & element )
100 { but element
101 DataType el = element; copying (pass
102 if ( table.retrieve( el ) ) { by value or here)
103 current = table.getcurrent( ); can be avoided
104 return true; altogether by
105 } making a find
106 function in
107 current = trailer; DLHashTable (an
108 return false; exercise)
109 }
211
find (cont.)
97 template <class DataType>
98 bool DoublyLinkedList<DataType>::find(
99 const DataType & element )
100 {
101 DataType el = element;
102 if ( table.retrieve( el ) ) {
103 current = table.getcurrent( );
104 return true;
105 }
106
107 current = trailer;
108 return false;
109 }
212
retrieve
110 template <class DataType>
111 bool DoublyLinkedList<DataType>::retrieve(
112 DataType & element )
113 {
114 if ( !find( element ) )
115 return false;
116
117 element = current->info;
118 return true;
119 }

213
remove
120 template <class DataType>
121 bool DoublyLinkedList<DataType>::remove(
122 DataType & element )
123 { sets element before
124 if ( !retrieve( element ) ) it is removed
125 return false;
126 current->dlback->dlnext = current->dlnext;
127 current->dlnext->dlback = current->dlback;
128 current = trailer;
129 table.remove( element );
130
131 return true;
132 }
214
remove (cont.)
120 template <class DataType>
121 bool DoublyLinkedList<DataType>::remove(
122 DataType & element )
123 { also sets current to the
124 if ( !retrieve( element ) ) node that element is in
125 return false;
126 current->dlback->dlnext = current->dlnext;
127 current->dlnext->dlback = current->dlback;
128 current = trailer;
129 table.remove( element );
130
131 return true;
132 }
215
remove (cont.)
120 template <class DataType>
121 bool DoublyLinkedList<DataType>::remove(
122 DataType & element )
123 { removes current node
124 if ( !retrieve( element ) ) from doubly-linked list
125 return false;
126 current->dlback->dlnext = current->dlnext;
127 current->dlnext->dlback = current->dlback;
128 current = trailer;
129 table.remove( element );
130
131 return true;
132 }
216
remove (cont.)
120 template <class DataType>
121 bool DoublyLinkedList<DataType>::remove( DataType & element )
122
123 {
124 if ( !retrieve( element ) )
125 return false;
126 current->dlback->dlnext = current->dlnext;
127 current->dlnext->dlback = current->dlback;
128 current = trailer;
129 table.remove( element );
130
131 return true; current
132 }
collision list

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

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

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

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

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

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

current collision list

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

current collision list

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

current collision list

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

current collision list

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

current collision list

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

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

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

230
deepCopy (cont.)
start at the end of the original doubly-linked list

166 Node<DataType> *originalptr = original.trailer->dlback;


167 if ( (originalptr == original.header) ||
168 !insert( originalptr->info ) )
169 return;

231
deepCopy (cont.)

166 Node<DataType> *originalptr = original.trailer->dlback;


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

232
deepCopy (cont.)

166 Node<DataType> *originalptr = original.trailer->dlback;


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

233
deepCopy (cont.)

166 Node<DataType> *originalptr = original.trailer->dlback;


167 if ( (originalptr == original.header) ||
168 !insert( originalptr->info ) )
169 return;
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.

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

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

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

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

238

Вам также может понравиться