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
 
15
    //variable to hold total number of collisions this run.
16
    //Definition: collision - the number of times we must jump to
17
    //                        get to the next null space in the table
18
    //                        This includes jumping NIL's
19
    //
20
    //NOTE: will only be counted on inserting values
7 irasnyd 21
    private int collisions; //initialized to 0 by default
5 irasnyd 22
 
7 irasnyd 23
    //create a HashTable with a certain capacity (maximum items)
24
    //and a maximum load factor (if we exceed this we will rehash)
5 irasnyd 25
    public HashTable(int capacity, float loadFactor) {
26
        entries = new Entry[capacity];
27
        this.loadFactor = loadFactor; }
28
 
7 irasnyd 29
    //create a HashTable with a certain capacity (maximum items)
30
    //and a default load factor of 0.75
5 irasnyd 31
    public HashTable(int capacity) {
7 irasnyd 32
        this(capacity,0.75F);} //calls the HashTable( int, float ) constructor
5 irasnyd 33
 
7 irasnyd 34
    //create a default HashTable with default capacity (101 items) and
35
    //default load factor of 0.75
5 irasnyd 36
    public HashTable() {
7 irasnyd 37
        this(101); } //calls the HashTable( int ) constructor
5 irasnyd 38
 
7 irasnyd 39
    //Method to find a certain key in the HashTable
40
    //Precondition: key != null
41
    //Postcondition: return the entry's value if the key is found
42
    //               otherwise return null for not found
5 irasnyd 43
    public Object get(Object key) {
44
        int h=hash(key);
45
        for (int i=0; i<entries.length; i++) {
46
            int j = nextProbe(h,i);
47
            Entry entry=entries[j];
48
            if (entry==null) break;
49
            if (entry==NIL) continue;
50
            if (entry.key.equals(key)) return entry.value;  // success
51
        }
52
        return null;  // failure: key not found
53
    }
6 irasnyd 54
 
7 irasnyd 55
    //Method to add a key/value pair to the HashTable
56
    //Key - the value that gets hash() called on it. Should be unique (hopefully)
57
    //Value - the actual data that is to be stored.
58
    //Precondition: key != null
59
    //Postcondition: return null if the object was inserted sucessfully
60
    //               return the value that was there if we updated a value
61
    //               return null if the table overflows (should never happen,
62
    //               but it is there just in case)
5 irasnyd 63
    public Object put(Object key, Object value) {
64
        if (used>loadFactor*entries.length) rehash();
7 irasnyd 65
        int h=hash(key); //hash the key
66
        for (int i=0; i<entries.length; i++) { //run once for each place in the Table
67
            int j = nextProbe(h,i); //get the [first, next] place to try putting the value
68
            Entry entry=entries[j]; //get the Entry at j (where we want to put value)
69
 
70
	    //if entry[j] == null then we have found a good place to put value!
71
	    if (entry==null) {
5 irasnyd 72
                entries[j] = new Entry(key,value);
73
                ++size;
74
                ++used;
75
                return null;  // insertion success
76
            }
7 irasnyd 77
 
78
	    //if entry[j] == NIL then we must continue to probe for a new place,
79
	    //otherwise we will confuse the remove() and get() methods
9 irasnyd 80
            if (entry==NIL) { collisions++; continue; }
7 irasnyd 81
 
82
	    //if entry[j].key == key then we need to update the record
5 irasnyd 83
            if (entry.key.equals(key)) {
84
                Object oldValue=entry.value;
85
                entries[j].value = value;
86
                return oldValue;  // update success
87
            }
9 irasnyd 88
 
89
	    //if we get here, we have had a collision that is not a NIL,
90
	    //and is not an Entry that needs updating, therefore it is something
91
	    //else that hashes to the same value.  Therefore we must increment the
92
	    //collision counter
93
	    collisions++;
94
 
95
	}
5 irasnyd 96
        return null;  // failure: table overflow
97
    }
98
 
7 irasnyd 99
    //Method to remove a key/value pair from the table.  This will leave a NIL behind
100
    //Precondition: key != null
101
    //Postcondition: return the old value if the key was found, then put a NIL in it's place
102
    //               return null if the key was not found in the table.
5 irasnyd 103
    public Object remove(Object key) {
7 irasnyd 104
        int h=hash(key); //hash the key
105
        for (int i=0; i<entries.length; i++) { //run once for every place in the table
106
            int j = nextProbe(h,i); //find the [first, next] place to put the value
5 irasnyd 107
            Entry entry=entries[j];
7 irasnyd 108
 
109
            if (entry==null) break; //break out of the loop, since the key was not found
110
            if (entry==NIL) continue; //keep going, since we found a NIL
111
            if (entry.key.equals(key)) { //we found the key we are looking for...
112
                Object oldValue=entry.value; //save value to return
113
                entries[j] = NIL; //replace the value with a NIL
114
                --size; //decrement size
5 irasnyd 115
                return oldValue;  // success
116
            }
117
        }
118
        return null;  // failure: key not found
119
    }
120
 
7 irasnyd 121
    //Method to access private variable size
122
    //Precondition: none
123
    //Postcondition: return size
5 irasnyd 124
    public int size() {
125
        return size;
126
    }
127
 
9 irasnyd 128
    //Method to access private variable collisions
129
    //Precondition: none
130
    //Postcondition: return collisions
131
    public int collisions() {
132
    	return collisions;
133
    }
134
 
7 irasnyd 135
    //A private class which will hold a key/value pair
5 irasnyd 136
    private class Entry {
137
        Object key, value;
138
        Entry(Object k, Object v) { key=k; value=v; }
139
    }
140
 
7 irasnyd 141
    //our implementation of the hash() function. Takes the Object.hashCode() method
142
    //and chops off the sign bit
143
    //Precondition: None (we check for key == null)
144
    //Postcondition: throw an IllegalArgumentException() if the key == null
145
    //               return an integer hash for the given key
5 irasnyd 146
    private int hash(Object key) {
147
        if (key==null) throw new IllegalArgumentException();
148
        return (key.hashCode() & 0x7FFFFFFF) % entries.length;
149
    }
7 irasnyd 150
 
151
    //Method to implement linear probing
152
    //Precondition: h != null; i != null
153
    //Postcondition: return the next place to try and put the value
5 irasnyd 154
    private int nextProbe(int h, int i) {
155
        return (h + i)%entries.length;      // Linear Probing
8 irasnyd 156
 
157
    	//return (h + (i * 3 ))%entries.length; //Prime Probing ( p=3  )
158
	//return (h + (i * 5 ))%entries.length; //Prime Probing ( p=5  )
159
	//return (h + (i * 7 ))%entries.length; //Prime Probing ( p=7  )
160
	//return (h + (i * 11))%entries.length; //Prime Probing ( p=11 ) 
161
 
162
        //return (h + (i * i ))%entries.length; //Quadratic Probing
163
 
164
	// STILL NEED TO ADD DOUBLE HASHING IMPLEMENTATION HERE
165
 
5 irasnyd 166
    }
167
 
7 irasnyd 168
    //Method to rehash the entire table.  This will get rid of NIL's
169
    //Precondition: none
170
    //Postcondition: entries will be twice the size plus one (ensures odd size)
171
    //               all NIL will be gone
172
    //               all values will be re-hash()ed
5 irasnyd 173
    private void rehash() {
174
        Entry[] oldEntries = entries;
175
        entries = new Entry[2*oldEntries.length+1];
176
        for (int k=0; k<oldEntries.length; k++) {
177
            Entry entry=oldEntries[k];
178
            if (entry==null || entry==NIL) continue;
179
            int h=hash(entry.key);
180
            for (int i=0; i<entries.length; i++) {
181
                int j = nextProbe(h,i);
182
                if (entries[j]==null) {
183
                    entries[j] = entry;
184
                    break;
185
                }
186
            }
187
        }
188
        used = size;
189
    }
190
}