1 import java.util.AbstractSet;
2 import java.util.Iterator;
3 import java.util.NoSuchElementException;
4
5 /**
6 A hash set stores an unordered collection of objects, using
7 a hash table.
8 */
9 public class HashSet extends AbstractSet
10 {
11 private Node[] buckets;
12 private int size;
13
14 /**
15 Constructs a hash table.
16 @param bucketsLength the length of the buckets array
17 */
18 public HashSet(int bucketsLength)
19 {
20 buckets = new Node[bucketsLength];
21 size = 0;
22 }
23
24 /**
25 Tests for set membership.
26 @param x an object
27 @return true if x is an element of this set
28 */
29 public boolean contains(Object x)
30 {
31 int h = x.hashCode();
32 if (h < 0) h = -h;
33 h = h % buckets.length;
34
35 Node current = buckets[h];
36 while (current != null)
37 {
38 if (current.data.equals(x)) return true;
39 current = current.next;
40 }
41 return false;
42 }
43
44 /**
45 Adds an element to this set.
46 @param x an object
47 @return true if x is a new object, false if x was
48 already in the set
49 */
50 public boolean add(Object x)
51 {
52 int h = x.hashCode();
53 if (h < 0) h = -h;
54 h = h % buckets.length;
55
56 Node current = buckets[h];
57 while (current != null)
58 {
59 if (current.data.equals(x))
60 return false; // Already in the set
61 current = current.next;
62 }
63 Node newNode = new Node();
64 newNode.data = x;
65 newNode.next = buckets[h];
66 buckets[h] = newNode;
67 size++;
68 return true;
69 }
70
71 /**
72 Removes an object from this set.
73 @param x an object
74 @return true if x was removed from this set, false
75 if x was not an element of this set
76 */
77 public boolean remove(Object x)
78 {
79 int h = x.hashCode();
80 if (h < 0) h = -h;
81 h = h % buckets.length;
82
83 Node current = buckets[h];
84 Node previous = null;
85 while (current != null)
86 {
87 if (current.data.equals(x))
88 {
89 if (previous == null) buckets[h] = current.next;
90 else previous.next = current.next;
91 size--;
92 return true;
93 }
94 previous = current;
95 current = current.next;
96 }
97 return false;
98 }
99
100 /**
101 Returns an iterator that traverses the elements of this set.
102 @return a hash set iterator
103 */
104 public Iterator iterator()
105 {
106 return new HashSetIterator();
107 }
108
109 /**
110 Gets the number of elements in this set.
111 @return the number of elements
112 */
113 public int size()
114 {
115 return size;
116 }
117
118 class Node
119 {
120 public Object data;
121 public Node next;
122 }
123
124 class HashSetIterator implements Iterator
125 {
126 private int bucket;
127 private Node current;
128 private int previousBucket;
129 private Node previous;
130
131 /**
132 Constructs a hash set iterator that points to the
133 first element of the hash set.
134 */
135 public HashSetIterator()
136 {
137 current = null;
138 bucket = -1;
139 previous = null;
140 previousBucket = -1;
141 }
142
143 public boolean hasNext()
144 {
145 if (current != null && current.next != null)
146 return true;
147 for (int b = bucket + 1; b < buckets.length; b++)
148 if (buckets[b] != null) return true;
149 return false;
150 }
151
152 public Object next()
153 {
154 previous = current;
155 previousBucket = bucket;
156 if (current == null || current.next == null)
157 {
158 // Move to next bucket
159 bucket++;
160
161 while (bucket < buckets.length
162 && buckets[bucket] == null)
163 bucket++;
164 if (bucket < buckets.length)
165 current = buckets[bucket];
166 else
167 throw new NoSuchElementException();
168 }
169 else // Move to next element in bucket
170 current = current.next;
171 return current.data;
172 }
173
174 public void remove()
175 {
176 if (previous != null && previous.next == current)
177 previous.next = current.next;
178 else if (previousBucket < bucket)
179 buckets[bucket] = current.next;
180 else
181 throw new IllegalStateException();
182 current = previous;
183 bucket = previousBucket;
184 }
185 }
186 }