-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTableDoubleHash.java
213 lines (188 loc) · 6.91 KB
/
TableDoubleHash.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
public class TableDoubleHash < K , E >
{
// Invariant of the Table class:
// 1. The number of items in the table is in the instance variable manyItems.
// 2. The preferred location for an element with a given key is at index
// hash(key). If a collision occurs, then next-Index is used to search
// forward to find the next open address. When an open address is found
// at an index i, then the element itself is placed in data[i] and the
// elements key is placed at keys[i].
// 3. An index i that is not currently used has data[i] and key[i] set to
// null.
// 4. If an index i has been used at some point (now or in the past), then
// hasBeenUsed[i] is true; otherwise it is false.//
private int manyItems;
private Object[ ] keys;
private Object[ ] data;
private boolean[ ] hasBeenUsed;
/**
* Initialize an empty table with a specified capacity.
* @param <CODE>capacity</CODE>
* the capacity for this new open-address hash table
* <dt><b>Postcondition:</b><dd>
* This table is empty and has the specified capacity.
* @exception OutOfMemoryError
* Indicates insufficient memory for the specified capacity.
**/
public Table(int capacity)
{
// The manyItems instance variable is automatically set to zero.
// which is the correct initial value. The three arrays are allocated to
// be the specified capacity. The boolean array is automatically
// initialized to falses, and the other two arrays are automatically
// initialized to all null.
if (capacity <= 0)
throw new IllegalArgumentException("Capacity is negative");
keys = new Object[capacity];
data = new Object[capacity];
hasBeenUsed = new boolean[capacity];
}
/**
* Determines whether a specified key is in this table.
* @param <CODE>key</CODE>
* the non-null key to look for
* <dt><b>Precondition:</b><dd>
* <CODE>key</CODE> cannot be null.
* @return
* <CODE>true</CODE? (if this table contains an object with the specified
* key); <CODE>false</CODE> otherwise. Note that <CODE>key.equals( )</CODE>
* is used to compare the <CODE>key</CODE> to the keys that are in the
* table.
* @exception NullPointerException
* Indicates that <CODE>key</CODE> is null.
**/
public boolean containsKey(K key)
{
return findIndex(key) != -1;
}
private int findIndex(K key)
// Postcondition: If the specified key is found in the table, then the return
// value is the index of the specified key. Otherwise, the return value is -1.
{
int count = 0;
int i = hash(key);
while (count < data.length && hasBeenUsed[i])
{
if (key.equals(keys[i]))
return i;
count++;
i = nextIndex(i);
}
return -1;
}
/** Retrieves an object for a specified key.
* @param <CODE>key</CODE>
* the non-null key to look for
* <dt><b>Precondition:</b><dd>
* <CODE>key</CODE> cannot be null.
* @return
* a reference to the object with the specified <CODE>key</CODE (if this
* table contains an such an object); null otherwise. Note that
* <CODE>key.equals( )</CODE> is used to compare the <CODE>key</CODE>
* to the keys that are in the table.
* @exception NullPointerException
* Indicates that <CODE>key</CODE> is null.
**/
public E get(K key)
{
int index = findIndex(key);
if (index == -1)
return null;
else
return (E) data[index];
}
private int hash(Object key)
// The return value is a valid index of the tables arrays. The index is
// calculated as the remainder when the absolute value of the keys
// hash code is divided by the size of the tables arrays.
{
return Math.abs(key.hashCode( )) % data.length;
}
private int nextIndex(int i)
// The return value is normally i+1. But if i+1 is data.length, then the
// return value is zero instead.
{
if (i+1 == data.length)
return 0;
else
return i+1;
}
/**
* Add a new element to this table, using the specified key.
* @param <CODE>key</CODE>
* the non-null key to use for the new element
* @param <CODE>element</CODE>
* the new element thats being added to this table
* <dt><b>Precondition:</b><dd>
* If there is not already an element with the specified <CODE>key</CODE>,
* then this tables size must be less than its capacity
* (i.e., <CODE>size() < capacity()</CODE>). Also, neither <CODE>key</CODE>
* nor </CODE>element</CODE> is null.
* <dt><b>Postcondition:</b><dd>
* If this table already has an object with the specified <CODE>key</CODE>,
* then that object is replaced by </CODE>element</CODE>, and the return
* value is a reference to the replaced object. Otherwise, the new
* </CODE>element</CODE> is added with the specified <CODE>key</CODE>
* and the return value is null.
* @exception IllegalStateException
* Indicates that there is no room for a new object in this table.
* @exception NullPointerException
* Indicates that <CODE>key</CODE> or <CODE>element</CODE> is null.
**/
public E put(K key, E element)
{
int index = findIndex(key);
E answer;
if (index != -1)
{ // The key is already in the table.
answer = (E) data[index];
data[index] = element;
return answer;
}
else if (manyItems < data.length)
{ // The key is not yet in this Table.
index = hash(key);
while (keys[index] != null)
index = nextIndex(index);
keys[index] = key;
data[index] = element;
hasBeenUsed[index] = true;
manyItems++;
return null;
}
else
{ // The table is full.
throw new IllegalStateException("Table is full.");
}
}
/**
* Removes an object for a specified key.
* @param <CODE>key</CODE>
* the non-null key to look for
* <dt><b>Precondition:</b><dd>
* <CODE>key</CODE> cannot be null.
* <dt><b>Postcondition:</b><dd>
* If an object was found with the specified </CODE>key</CODE>, then that
* object has been removed from this table and a copy of the removed object
* is returned; otherwise, this table is unchanged and the null reference
* is returned. Note that
* <CODE>key.equals( )</CODE> is used to compare the <CODE>key</CODE>
* to the keys that are in the table.
* @exception NullPointerException
* Indicates that </CODE>key</CODE> is null.
**/
public E remove(K key)
{
int index = findIndex(key);
E answer = null;
if (index != -1)
{
answer = (E) data[index];
keys[index] = null;
data[index] = null;
manyItems--;
}
return answer;
}
}
}