5
5
import java .util .stream .Collectors ;
6
6
7
7
/**
8
- * Implementation of a HashSet that uses Open Addressing to resolve collisions.
8
+ * Implementation of a HashSet that uses Open Addressing and linear probing to resolve collisions.
9
9
*
10
10
* <p>The time complexity of operations in this HashSet implementation consists of two components. Firstly, there is the time to
11
11
* compute the hash value, which is typically a constant-time operation. Secondly, there is the time to access the corresponding
12
- * bucket, which involves traversing the linked list in case of collisions. On average, these operations have a constant-time
13
- * complexity.
12
+ * bucket, which involves probing the buckets using linear probing.
14
13
*
15
14
* <p>Public methods (along with their time-complexity):
16
15
* boolean add(T element) adds the given element into the HashSet. Expected O(1) assuming SUHA.
@@ -29,6 +28,7 @@ public class HashSet<T>{
29
28
private final int ELEMENT_NOT_FOUND = -1 ;
30
29
private int size ; // Number of elements present in the Set (its cardinality).
31
30
private T [] buckets ;
31
+ private final T TOMBSTONE ;
32
32
33
33
/**
34
34
* Creates a HashSet with an initial capacity of 16.
@@ -40,6 +40,11 @@ public HashSet() {
40
40
T [] tempBuckets = (T []) new Object [INITIAL_CAPACITY ];
41
41
this .buckets = tempBuckets ;
42
42
this .size = 0 ;
43
+
44
+ // There is no way to retrieve an instance of Tombstone. Therefore, it is safe to cast Tombstone to T.
45
+ @ SuppressWarnings ("unchecked" )
46
+ T tempVar = (T ) Tombstone .TOMBSTONE ;
47
+ this .TOMBSTONE = tempVar ;
43
48
}
44
49
45
50
/**
@@ -76,7 +81,7 @@ public boolean remove(T element) {
76
81
if (bucketIndex == ELEMENT_NOT_FOUND ) {
77
82
return false ; // If the index returned by the probe function contains an empty bucket, then the element is not present in the set.
78
83
}
79
- this .buckets [bucketIndex ] = this .tombstone () ; // marks the current bucket with a TOMBSTONE.
84
+ this .buckets [bucketIndex ] = this .TOMBSTONE ; // marks the current bucket with a TOMBSTONE.
80
85
this .size --;
81
86
return true ;
82
87
}
@@ -124,7 +129,7 @@ public int size() {
124
129
*/
125
130
public List <T > toList () {
126
131
return Arrays .stream (this .buckets )
127
- .filter (element -> element != null || this .tombstone () .equals (element ))
132
+ .filter (element -> element != null || this .TOMBSTONE .equals (element ))
128
133
.collect (Collectors .toList ());
129
134
}
130
135
@@ -208,14 +213,6 @@ private int search(T element) {
208
213
return ELEMENT_NOT_FOUND ; // element is not in the HashSet.
209
214
}
210
215
211
- // This method returns an instance of Tombstone, which is used to mark removed elements.
212
- private T tombstone () {
213
- // There is no way to retrieve an instance of Tombstone. Therefore, it is safe to cast Tombstone to T.
214
- @ SuppressWarnings ("unchecked" )
215
- T deleted = (T ) Tombstone .TOMBSTONE ;
216
- return deleted ;
217
- }
218
-
219
216
/**
220
217
* Returns true if the bucket at the given bucketIndex contains no elements (Either null or Tombstone).
221
218
*
@@ -243,7 +240,7 @@ private boolean isNullBucket(int bucketIndex) {
243
240
* @return true if the bucket contains a Tombstone at the given bucketIndex.
244
241
*/
245
242
private boolean isTombstoneBucket (int bucketIndex ) {
246
- return this .tombstone () .equals (this .buckets [bucketIndex ]);
243
+ return this .TOMBSTONE .equals (this .buckets [bucketIndex ]);
247
244
}
248
245
249
246
/**
0 commit comments