Download presentation
Presentation is loading. Please wait.
Published byFrederick Williamson Modified over 9 years ago
9
RED-BLACK TREE SEARCH THE FOLLOWING METHOD IS IN TreeMap.java:
56
IMPLEMENTATION OF THE HashMap CLASS
57
public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException ("Illegal Initial Capacity: "+ initialCapacity); if (loadFactor <= 0) throw new IllegalArgumentException ("Illegal Load factor: "+ loadFactor); if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry[initialCapacity]; threshold = (int)(initialCapacity * loadFactor); } // constructor
58
FOR THE containsKey, get, put, AND remove METHODS, THE INITIAL STRATEGY IS THE SAME: HASH key TO index ; SEARCH LINKED LIST AT table [index].
70
TIME ESTIMATES: LET n = count, LET m = table.length. ASSUME THE UNIFORM HASHING ASSUMPTION HOLDS.
71
THE AVERAGE SIZE OF EACH LIST IS n / m
72
FOR THE containsKey METHOD, averageTime S (n, m) n / 2m iterations. BUT n / m <= loadFactor, A CONSTANT (ASSIGNED IN THE CONSTRUCTOR) SO averageTime S (n, m) < A CONSTANT. averageTime S (n, m) IS CONSTANT.
76
FIELDS IN THE HashIterator CLASS: Entry[ ] table = HashMap.this.table; int index = table.length; START AT BACK Entry entry = null; Entry lastReturned = null; // where the iterator is // currently positioned int type; // 0 for keys, 1 for values, 2 for entries private int expectedModCount = modCount;
77
public boolean hasNext() { while (entry==null && index>0) entry = table[--index]; return entry != null; } // method hasNext
78
public Object next( ) { if (modCount != expectedModCount) throw new ConcurrentModificationException( ); while (entry==null && index>0) entry = table[--index]; if (entry != null) { Entry e = lastReturned = entry; entry = e.next; return type == KEYS ? e.key : (type == VALUES ? e.value : e); } // non-null entry throw new NoSuchElementException( ); } // method next
86
214-30-3261 033-51-8000 214-19-9528 819-02-9528 KEYS 819-02-9261 033-30-8262 215-09-1766 214-17-0261 260 null 261 214-30-3261 262 819-02-9261 PART OF table 263 033-30-8262 264 214-17-0261 265 null
87
remove (new Integer (214303261)); 260 null 261 null 262 819-02-9261 263 033-30-8262 264 214-17-0261 265 null containsKey ( new Integer (214170261)) WILL RETURN false BECAUSE INDEX 261 HAS null.
88
SOLUTION: boolean markedForRemoval; put SETS markedForRemoval TO false; remove SETS markedForRemoval TO true.
89
AFTER INITIAL PUTS: 260 null 261 214-30-3261 false 262 819-02-9261 false 263 033-30-8262 false 264 214-17-0261 false 265 null
90
AFTER remove ( new Integer (214303261)); 260 null 261 214-30-3261 true 262 819-02-9261 false 263 033-30-8262 false 264 214-17-0261 false 265 null
91
HERE IS PART OF remove : Entry e = table [index]; if (!e.markedForRemoval && e.hash == hash && key.equals(e.key)) { count--; Object oldValue = e.value; e.markedForRemoval = true; return oldValue; } // if match index = (index + 1) % table.length; OFFSET OF 1
92
THIS SOLUTION LEADS TO ANOTHER PROBLEM: SUPPOSE table.length = 1000 put remove ( put AND remove A TOTAL OF 950 TIMES) … put (REPEATED 40 TIMES) count = 40, SO NO NEED TO RE-HASH
94
TOO MANY!
95
SOLUTION: KEEP TRACK OF REMOVALS: private transient int countPlus; // the value of count + the // number of removals since // table.length was last changed public Object put(Object key, Object value) {... if (countPlus >= threshold) rehash( );...
96
private void rehash( ) { … for (int i = 0; i < oldCapacity ; i++) if (oldMap [i] != null && !oldMap [i].markedForRemoval) put (oldMap [i].key, oldMap [i].value); …
97
private void rehash( ) { DON’T REHASH IF … MARKED FOR REMOVAL for (int i = 0; i < oldCapacity ; i++) if (oldMap [i] != null && !oldMap [i].markedForRemoval) put (oldMap [i].key, oldMap [i].value); …
98
CLUSTER: A SEQUENCE OF NON-EMPTY LOCATIONS 260 null 261 214-30-3261 false 262 819-02-9261 false 263 033-30-8262 false 264 214-17-0261 false 265 null KEYS THAT HASH TO 261 FOLLOW THE SAME PATH AS KEYS THAT HASH TO 262, …
100
SOLUTION: DOUBLE HASHING, THAT IS, OBTAIN BOTH INDICES AND OFFSETS BY HASHING: index = hash & 0x7FFFFFFF % table.length; offset = hash & 0x7FFFFFFF / table.length; NOW THE OFFSET DEPENDS ON THE KEY, SO DIFFERENT KEYS WILL USU- ALLY HAVE DIFFERENT OFFSETS, SO NO MORE PRIMARY CLUSTERING!
101
TO GET A NEW INDEX: index = (index + offset) % table.length;
102
EXAMPLE: table.length = 11 key index offset 15 41 1981 1651 5835 2752 3523 3082 4734 WHERE WOULD THESE KEYS GO IN table ?
103
index key 047 1 235 358 415 516 6 727 819 9 1030
104
PROBLEM: WHAT IF OFFSET IS MULTIPLE OF table.length ? EXAMPLE: table.length = 11 key index offset 15 41 1981 1651 5835 2752 3523 4734 246422 // BUT 15 IS AT INDEX 4 FOR KEY 246, NEW INDEX = (4 + 22) % 11 = 4. OOPS!
105
SOLUTION : if (offset % table.length == 0) offset = 1; ON AVERAGE, offset % table.length WILL EQUAL 0 ONLY ONCE IN EVERY table.length TIMES.
106
PROBLEM: WHAT IF table.length HAS SEVERAL FACTORS? EXAMPLE: table.length = 20 key index offset 200 1 25 5 1 30 10 1 35 15 1 110 10 5 // BUT 30 IS AT INDEX 10 FOR KEY 110, NEW INDEX = (10 + 5) % 20 = 15, WHICH IS OCCUPIED, SO NEW INDEX = (15 + 5) % 20, WHICH IS OCCUPIED, SO NEW INDEX =...
107
SOLUTION: MAKE table.length A PRIME.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.