001: import java.util.Iterator;
002: import java.util.AbstractSet;
003: 
004: /**
005:    A hash set stores an unordered collection of objects, using
006:    a hash table.
007: */
008: public class HashSet extends AbstractSet
009: {
010:    /**
011:       Constructs a hash table.
012:       @param bucketsLength the length of the buckets array
013:    */
014:    public HashSet(int bucketsLength)
015:    {
016:       buckets = new Link[bucketsLength];
017:       size = 0;
018:    }
019: 
020:    /**
021:       Tests for set membership.
022:       @param x an object
023:       @return true if x is an element of this set
024:    */
025:    public boolean contains(Object x)
026:    {
027:       int h = x.hashCode();
028:       if (h < 0) h = -h;
029:       h = h % buckets.length;
030:       
031:       Link current = buckets[h];
032:       while (current != null)
033:       {
034:          if (current.data.equals(x)) return true;
035:          current = current.next;
036:       }
037:       return false;
038:    }
039: 
040:    /**
041:       Adds an element to this set.
042:       @param x an object
043:       @return true if x is a new object, false if x was
044:       already in the set
045:    */
046:    public boolean add(Object x)
047:    {
048:       int h = x.hashCode();
049:       if (h < 0) h = -h;
050:       h = h % buckets.length;
051:       
052:       Link current = buckets[h];
053:       while (current != null)
054:       {
055:          if (current.data.equals(x)) 
056:             return false; // already in the set
057:          current = current.next;
058:       }
059:       Link newLink = new Link();
060:       newLink.data = x;
061:       newLink.next = buckets[h];
062:       buckets[h] = newLink;
063:       size++;
064:       return true;
065:    }
066: 
067:    /**
068:       Removes an object from this set.
069:       @param x an object
070:       @return true if x was removed from this set, false
071:       if x was not an element of this set
072:    */
073:    public boolean remove(Object x)
074:    {
075:       int h = x.hashCode();
076:       if (h < 0) h = -h;
077:       h = h % buckets.length;
078:       
079:       Link current = buckets[h];
080:       Link previous = null;
081:       while (current != null)
082:       {
083:          if (current.data.equals(x)) 
084:          {
085:             if (previous == null) buckets[h] = current.next;
086:             else previous.next = current.next;
087:             size--;
088:             return true;
089:          }
090:          previous = current;
091:          current = current.next;
092:       }
093:       return false;
094:    }
095: 
096:    /**
097:       Returns an iterator that traverses the elements of this set.
098:       @param a hash set iterator
099:    */
100:    public Iterator iterator()
101:    {
102:       return new HashSetIterator();
103:    }
104: 
105:    /**
106:       Gets the number of elements in this set.
107:       @return the number of elements
108:    */
109:    public int size()
110:    {
111:       return size;
112:    }
113: 
114:    private Link[] buckets;
115:    private int size;
116: 
117:    private class Link
118:    {
119:       public Object data;
120:       public Link next;
121:    }
122: 
123:    private class HashSetIterator implements Iterator
124:    {
125: 
126:       /**
127:          Constructs a hash set iterator that points to the
128:          first element of the hash set.
129:       */
130:       public HashSetIterator()
131:       {
132:          bucket = 0;
133:          previous = null;
134:          previousBucket = buckets.length;
135: 
136:          // set bucket to the index of the first nonempty bucket
137:          while (bucket < buckets.length && buckets[bucket] == null)
138:             bucket++;
139:          if (bucket < buckets.length) current = buckets[bucket];
140:          else current = null;
141:       }
142:       
143:       public boolean hasNext()
144:       {
145:          return current != null;
146:       }
147:        
148:       public Object next()
149:       {
150:          Object r = current.data;
151: 
152:          if (current.next == null) // move to next bucket
153:          {
154:             previousBucket = bucket;
155:             bucket++;
156: 
157:             while (bucket < buckets.length && buckets[bucket] == null)
158:                bucket++;
159:             if (bucket < buckets.length) 
160:                current = buckets[bucket];
161:             else
162:                current = null;
163:          }
164:          else // move to next element in bucket 
165:          {
166:             previous = current;
167:             current = current.next;            
168:          }
169: 
170:          return r;
171:       }
172: 
173:       public void remove()
174:       {
175:          if (previous != null)
176:             previous.next = previous.next.next;
177:          else if (previousBucket < buckets.length)
178:             buckets[previousBucket] = null;
179:          else 
180:             throw new IllegalStateException();
181:          previous = null;
182:          previousBucket = buckets.length;
183:       }
184: 
185:       private int bucket;
186:       private Link current;
187:       private int previousBucket;
188:       private Link previous;
189:    }
190: }