Subversion Repositories programming

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5 irasnyd 1
//import chap09.list03.Map;
2
 
3
import java.io.*;
4
import java.util.*;
5
 
6
public class HashTable implements Map {  // open addressing
7 irasnyd 7
    private Entry[] entries; 
8
 
9
    //size is the total number of elements, including NIL
10
    //used is the total number of elements, NOT INCLUDING NIL
5 irasnyd 11
    private int size, used;
12
    private float loadFactor;
13
    private final Entry NIL = new Entry(null,null);  // dummy
9 irasnyd 14
 
10 irasnyd 15
    private int probeType; //holds the type of probing to use    
16
 
9 irasnyd 17
    //variable to hold total number of collisions this run.
18
    //Definition: collision - the number of times we must jump to
19
    //                        get to the next null space in the table
20
    //                        This includes jumping NIL's
21
    //
22
    //NOTE: will only be counted on inserting values
7 irasnyd 23
    private int collisions; //initialized to 0 by default
5 irasnyd 24
 
7 irasnyd 25
    //create a HashTable with a certain capacity (maximum items)
26
    //and a maximum load factor (if we exceed this we will rehash)
5 irasnyd 27
    public HashTable(int capacity, float loadFactor) {
28
        entries = new Entry[capacity];
29
        this.loadFactor = loadFactor; }
30
 
7 irasnyd 31
    //create a HashTable with a certain capacity (maximum items)
32
    //and a default load factor of 0.75
5 irasnyd 33
    public HashTable(int capacity) {
7 irasnyd 34
        this(capacity,0.75F);} //calls the HashTable( int, float ) constructor
5 irasnyd 35
 
7 irasnyd 36
    //create a default HashTable with default capacity (101 items) and
37
    //default load factor of 0.75
5 irasnyd 38
    public HashTable() {
7 irasnyd 39
        this(101); } //calls the HashTable( int ) constructor
5 irasnyd 40
 
7 irasnyd 41
    //Method to find a certain key in the HashTable
42
    //Precondition: key != null
43
    //Postcondition: return the entry's value if the key is found
44
    //               otherwise return null for not found
5 irasnyd 45
    public Object get(Object key) {
46
        int h=hash(key);
47
        for (int i=0; i<entries.length; i++) {
48
            int j = nextProbe(h,i);
49
            Entry entry=entries[j];
50
            if (entry==null) break;
51
            if (entry==NIL) continue;
52
            if (entry.key.equals(key)) return entry.value;  // success
53
        }
54
        return null;  // failure: key not found
55
    }
6 irasnyd 56
 
7 irasnyd 57
    //Method to add a key/value pair to the HashTable
58
    //Key - the value that gets hash() called on it. Should be unique (hopefully)
59
    //Value - the actual data that is to be stored.
60
    //Precondition: key != null
61
    //Postcondition: return null if the object was inserted sucessfully
62
    //               return the value that was there if we updated a value
63
    //               return null if the table overflows (should never happen,
64
    //               but it is there just in case)
5 irasnyd 65
    public Object put(Object key, Object value) {
66
        if (used>loadFactor*entries.length) rehash();
11 irasnyd 67
 
16 irasnyd 68
        System.out.print(key); //print out the key
69
 
70
        int h=hash(key); //hash the key
11 irasnyd 71
 
16 irasnyd 72
        for (int i=0; i<entries.length; i++) { //run once for each place in the Table
7 irasnyd 73
            int j = nextProbe(h,i); //get the [first, next] place to try putting the value
74
            Entry entry=entries[j]; //get the Entry at j (where we want to put value)
75
 
16 irasnyd 76
            System.out.print(" -> " + j); //print the location we tried to place the value
77
 
78
            //if entry[j] == null then we have found a good place to put value!
79
            if (entry==null) {
80
 
11 irasnyd 81
                System.out.println(); //terminate the line
16 irasnyd 82
 
5 irasnyd 83
                entries[j] = new Entry(key,value);
84
                ++size;
85
                ++used;
86
                return null;  // insertion success
87
            }
16 irasnyd 88
 
89
            //if entry[j] == NIL then we must continue to probe for a new place,
90
            //otherwise we will confuse the remove() and get() methods
9 irasnyd 91
            if (entry==NIL) { collisions++; continue; }
7 irasnyd 92
 
16 irasnyd 93
            //if entry[j].key == key then we need to update the record
5 irasnyd 94
            if (entry.key.equals(key)) {
95
                Object oldValue=entry.value;
96
                entries[j].value = value;
97
                return oldValue;  // update success
98
            }
9 irasnyd 99
 
16 irasnyd 100
            //if we get here, we have had a collision that is not a NIL,
101
            //and is not an Entry that needs updating, therefore it is something
102
            //else that hashes to the same value.  Therefore we must increment the
103
            //collision counter
104
            collisions++;
105
 
106
        } //end for loop
107
 
108
    return null;  // failure: table overflow
109
    } //end put()
5 irasnyd 110
 
7 irasnyd 111
    //Method to remove a key/value pair from the table.  This will leave a NIL behind
112
    //Precondition: key != null
113
    //Postcondition: return the old value if the key was found, then put a NIL in it's place
114
    //               return null if the key was not found in the table.
5 irasnyd 115
    public Object remove(Object key) {
7 irasnyd 116
        int h=hash(key); //hash the key
117
        for (int i=0; i<entries.length; i++) { //run once for every place in the table
118
            int j = nextProbe(h,i); //find the [first, next] place to put the value
5 irasnyd 119
            Entry entry=entries[j];
7 irasnyd 120
 
121
            if (entry==null) break; //break out of the loop, since the key was not found
122
            if (entry==NIL) continue; //keep going, since we found a NIL
123
            if (entry.key.equals(key)) { //we found the key we are looking for...
124
                Object oldValue=entry.value; //save value to return
125
                entries[j] = NIL; //replace the value with a NIL
126
                --size; //decrement size
5 irasnyd 127
                return oldValue;  // success
128
            }
129
        }
130
        return null;  // failure: key not found
131
    }
132
 
7 irasnyd 133
    //Method to access private variable size
134
    //Precondition: none
135
    //Postcondition: return size
5 irasnyd 136
    public int size() {
137
        return size;
138
    }
139
 
9 irasnyd 140
    //Method to access private variable collisions
141
    //Precondition: none
142
    //Postcondition: return collisions
143
    public int collisions() {
16 irasnyd 144
        return collisions;
9 irasnyd 145
    }
146
 
10 irasnyd 147
    //Method to set the probeType variable
148
    //
149
    //0 == Linear Probing (step size 1) DEFAULT
150
    //1 == Prime  Probing (step size 3)
151
    //2 == Prime  Probing (step size 5)
152
    //3 == Prime  Probing (step size 7)
153
    //4 == Prime  Probing (step size 11)
154
    //5 == Quadratic Probing
155
    //6 == Double Hashing
156
    //
157
    //Precondition: 0 <= newValue <= 6
158
    //Postcondition: probeType will be changed
159
    //WARNING: Please do NOT change probeType while in a test run
160
    public void setProbeType( int newValue ) {
16 irasnyd 161
        if( newValue < 0 || newValue > 6 ) { newValue = 0; } //put in for safety, just in case
162
        probeType = newValue;
10 irasnyd 163
    }
164
 
7 irasnyd 165
    //A private class which will hold a key/value pair
5 irasnyd 166
    private class Entry {
167
        Object key, value;
168
        Entry(Object k, Object v) { key=k; value=v; }
169
    }
170
 
7 irasnyd 171
    //our implementation of the hash() function. Takes the Object.hashCode() method
172
    //and chops off the sign bit
173
    //Precondition: None (we check for key == null)
174
    //Postcondition: throw an IllegalArgumentException() if the key == null
175
    //               return an integer hash for the given key
5 irasnyd 176
    private int hash(Object key) {
177
        if (key==null) throw new IllegalArgumentException();
178
        return (key.hashCode() & 0x7FFFFFFF) % entries.length;
179
    }
7 irasnyd 180
 
181
    //Method to implement linear probing
182
    //Precondition: h != null; i != null
183
    //Postcondition: return the next place to try and put the value
5 irasnyd 184
    private int nextProbe(int h, int i) {
10 irasnyd 185
 
16 irasnyd 186
    int returnVal = 0; //set to zero to stop compiler error
8 irasnyd 187
 
16 irasnyd 188
    switch( probeType ) {
17 irasnyd 189
        case 0: //linear probing
16 irasnyd 190
            returnVal = (h + i)%entries.length;
191
            break;
17 irasnyd 192
        case 1: //Prime Probing ( p=3  )
16 irasnyd 193
            returnVal = (h + (i * 3 ))%entries.length; 
194
            break;
17 irasnyd 195
        case 2: //Prime Probing ( p=5  )
16 irasnyd 196
            returnVal = (h + (i * 5 ))%entries.length;
197
            break;
17 irasnyd 198
        case 3: //Prime Probing ( p=7  )
16 irasnyd 199
            returnVal = (h + (i * 7 ))%entries.length;
200
            break;
17 irasnyd 201
        case 4: //Prime Probing ( p=11 )
16 irasnyd 202
            returnVal = (h + (i * 11))%entries.length;
203
            break;
17 irasnyd 204
        case 5: //Quadratic Probing
16 irasnyd 205
            returnVal = (h + (i * i ))%entries.length;
206
            break;
207
        //I am aware that my implementation of Double Hashing (which follows) is
208
        //wasteful in terms of computation time (we must create the array "step"
209
        //each and every time this code is run.  I did it this way to abstract the
210
        //method used to find the nextProbe() location from the put method.
17 irasnyd 211
        case 6: //Double Hashing
16 irasnyd 212
            int[] step = { 2,3,5,7,11 };
213
            int stepSize = step[h%4];
214
            returnVal = (h + (i * stepSize))%entries.length;
215
            break;
216
    }
217
    //return the final value
218
    return returnVal;
8 irasnyd 219
 
5 irasnyd 220
    }
221
 
7 irasnyd 222
    //Method to rehash the entire table.  This will get rid of NIL's
223
    //Precondition: none
224
    //Postcondition: entries will be twice the size plus one (ensures odd size)
225
    //               all NIL will be gone
226
    //               all values will be re-hash()ed
5 irasnyd 227
    private void rehash() {
228
        Entry[] oldEntries = entries;
229
        entries = new Entry[2*oldEntries.length+1];
230
        for (int k=0; k<oldEntries.length; k++) {
231
            Entry entry=oldEntries[k];
232
            if (entry==null || entry==NIL) continue;
233
            int h=hash(entry.key);
234
            for (int i=0; i<entries.length; i++) {
235
                int j = nextProbe(h,i);
236
                if (entries[j]==null) {
237
                    entries[j] = entry;
238
                    break;
239
                }
240
            }
241
        }
242
        used = size;
243
    }
244
}
18 irasnyd 245