码迷,mamicode.com
首页 > 其他好文 > 详细

重写Object.hashCode如何提高hashtable的效率

时间:2015-04-25 19:38:39      阅读:255      评论:0      收藏:0      [点我收藏+]

标签:

首先,我个人对Hash算法不熟悉,参考了这位大神的博客:

http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html

粗略的理解是,Hash算法在分块的时候,如果分的过多会导致查找元素效率低。并做了以下的实验:

技术分享
  1 /*
  2  * Copyright 2001-2004 The Apache Software Foundation.
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *     http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 /*
 17  * $Id: Hashtable.java,v 1.2.4.1 2005/09/06 11:05:18 pvedula Exp $
 18  */
 19 
 20 import java.awt.List;
 21 import java.util.ArrayList;
 22 import java.util.Collection;
 23 import java.util.Collections;
 24 import java.util.Comparator;
 25 import java.util.Enumeration;
 26 import java.util.HashMap;
 27 import java.util.HashSet;
 28 import java.util.TreeMap;
 29 
 30 /**
 31  * IMPORTANT NOTE:
 32  * This code was taken from Sun‘s Java1.1 JDK java.util.HashTable.java
 33  * All "synchronized" keywords and some methods we do not need have been 
 34  * all been removed.
 35  */
 36 
 37 /**
 38  * Object that wraps entries in the hash-table
 39  * 
 40  * @author Morten Jorgensen
 41  */
 42 class HashtableEntry {
 43     int hash;
 44     Object key;
 45     Object value;
 46     HashtableEntry next;
 47 
 48     protected Object clone() {
 49         HashtableEntry entry = new HashtableEntry();
 50         entry.hash = hash;
 51         entry.key = key;
 52         entry.value = value;
 53         entry.next = (next != null) ? (HashtableEntry) next.clone() : null;
 54         return entry;
 55     }
 56 }
 57 
 58 /**
 59  * The main hash-table implementation
 60  */
 61 public class MyHashTable {
 62 
 63     private transient HashtableEntry table[]; // hash-table entries
 64     private transient int count; // number of entries
 65     private int threshold; // current size of hash-tabke
 66     private float loadFactor; // load factor
 67 
 68     private HashMap<Integer, Integer> indexcount = new HashMap<Integer, Integer>();
 69 
 70     /**
 71      * Constructs a new, empty hashtable with the specified initial capacity and
 72      * the specified load factor.
 73      */
 74     public MyHashTable(int initialCapacity, float loadFactor) {
 75         if (initialCapacity <= 0)
 76             initialCapacity = 11;
 77         if (loadFactor <= 0.0)
 78             loadFactor = 0.75f;
 79         this.loadFactor = loadFactor;
 80         table = new HashtableEntry[initialCapacity];
 81         threshold = (int) (initialCapacity * loadFactor);
 82     }
 83 
 84     /**
 85      * Constructs a new, empty hashtable with the specified initial capacity and
 86      * default load factor.
 87      */
 88     public MyHashTable(int initialCapacity) {
 89         this(initialCapacity, 0.75f);
 90     }
 91 
 92     /**
 93      * Constructs a new, empty hashtable with a default capacity and load
 94      * factor.
 95      */
 96     public MyHashTable() {
 97         this(101, 0.75f);
 98     }
 99 
100     /**
101      * Returns the number of keys in this hashtable.
102      */
103     public int size() {
104         return count;
105     }
106 
107     /**
108      * Tests if this hashtable maps no keys to values.
109      */
110     public boolean isEmpty() {
111         return count == 0;
112     }
113 
114     /**
115      * Returns an enumeration of the keys in this hashtable.
116      */
117     public Enumeration keys() {
118         return new HashtableEnumerator(table, true);
119     }
120 
121     /**
122      * Returns an enumeration of the values in this hashtable. Use the
123      * Enumeration methods on the returned object to fetch the elements
124      * sequentially.
125      */
126     public Enumeration elements() {
127         return new HashtableEnumerator(table, false);
128     }
129 
130     /**
131      * Tests if some key maps into the specified value in this hashtable. This
132      * operation is more expensive than the <code>containsKey</code> method.
133      */
134     public boolean contains(Object value) {
135 
136         if (value == null)
137             throw new NullPointerException();
138 
139         int i;
140         HashtableEntry e;
141         HashtableEntry tab[] = table;
142 
143         for (i = tab.length; i-- > 0;) {
144             for (e = tab[i]; e != null; e = e.next) {
145                 if (e.value.equals(value)) {
146                     return true;
147                 }
148             }
149         }
150         return false;
151     }
152 
153     /**
154      * Tests if the specified object is a key in this hashtable.
155      */
156     public boolean containsKey(Object key) {
157         HashtableEntry e;
158         HashtableEntry tab[] = table;
159         int hash = key.hashCode();
160         int index = (hash & 0x7FFFFFFF) % tab.length;
161 
162         for (e = tab[index]; e != null; e = e.next)
163             if ((e.hash == hash) && e.key.equals(key))
164                 return true;
165 
166         return false;
167     }
168 
169     /**
170      * Returns the value to which the specified key is mapped in this hashtable.
171      */
172     public Object get(Object key) {
173         HashtableEntry e;
174         HashtableEntry tab[] = table;
175         int hash = key.hashCode();
176         int index = (hash & 0x7FFFFFFF) % tab.length;
177 
178         for (e = tab[index]; e != null; e = e.next)
179             if ((e.hash == hash) && e.key.equals(key))
180                 return e.value;
181 
182         return null;
183     }
184 
185     /**
186      * Rehashes the contents of the hashtable into a hashtable with a larger
187      * capacity. This method is called automatically when the number of keys in
188      * the hashtable exceeds this hashtable‘s capacity and load factor.
189      */
190     protected void rehash() {
191         HashtableEntry e, old;
192         int i, index;
193         int oldCapacity = table.length;
194         HashtableEntry oldTable[] = table;
195 
196         int newCapacity = oldCapacity * 2 + 1;
197         HashtableEntry newTable[] = new HashtableEntry[newCapacity];
198 
199         threshold = (int) (newCapacity * loadFactor);
200         table = newTable;
201 
202         for (i = oldCapacity; i-- > 0;) {
203             for (old = oldTable[i]; old != null;) {
204                 e = old;
205                 old = old.next;
206                 index = (e.hash & 0x7FFFFFFF) % newCapacity;
207                 e.next = newTable[index];
208                 newTable[index] = e;
209             }
210         }
211     }
212 
213     /**
214      * Maps the specified <code>key</code> to the specified <code>value</code>
215      * in this hashtable. Neither the key nor the value can be <code>null</code>
216      * .
217      * <p>
218      * The value can be retrieved by calling the <code>get</code> method with a
219      * key that is equal to the original key.
220      */
221     public Object put(Object key, Object value) {
222         // Make sure the value is not null
223         if (value == null)
224             throw new NullPointerException();
225 
226         // Makes sure the key is not already in the hashtable.
227         HashtableEntry e;
228         HashtableEntry tab[] = table;
229         int hash = key.hashCode();
230         int index = (hash & 0x7FFFFFFF) % tab.length;
231         if (indexcount.get(Integer.valueOf(index)) != null) {
232             indexcount.put(Integer.valueOf(index),
233                     indexcount.get(Integer.valueOf(index)) + 1);
234         } else {
235             indexcount.put(Integer.valueOf(index), 1);
236         }
237 
238         for (e = tab[index]; e != null; e = e.next) {
239             if ((e.hash == hash) && e.key.equals(key)) {
240                 Object old = e.value;
241                 e.value = value;
242                 return old;
243             }
244         }
245 
246         // Rehash the table if the threshold is exceeded
247         if (count >= threshold) {
248             rehash();
249             return put(key, value);
250         }
251 
252         // Creates the new entry.
253         e = new HashtableEntry();
254         e.hash = hash;
255         e.key = key;
256         e.value = value;
257         e.next = tab[index];
258         tab[index] = e;
259         count++;
260         return null;
261     }
262 
263     public void printIndexCount() {
264         Collection<Integer> values = indexcount.values();
265         ArrayList<Integer> arrays = new ArrayList<Integer>(values);
266         Collections.sort(arrays,new Comparator<Integer>() {
267 
268             @Override
269             public int compare(Integer o1, Integer o2) {
270                 return o2.compareTo(o1);
271             }
272         });
273         HashMap<Integer, Integer> hMap = new HashMap<Integer, Integer>();
274         for (Integer integer : arrays) {
275             if(hMap.containsKey(integer)){
276                 hMap.put(integer, hMap.get(integer)+1);
277             }else{
278                 hMap.put(integer, 1);
279             }
280         }
281         System.out.println(hMap);
282     }
283 
284     /**
285      * Removes the key (and its corresponding value) from this hashtable. This
286      * method does nothing if the key is not in the hashtable.
287      */
288     public Object remove(Object key) {
289         HashtableEntry e, prev;
290         HashtableEntry tab[] = table;
291         int hash = key.hashCode();
292         int index = (hash & 0x7FFFFFFF) % tab.length;
293         for (e = tab[index], prev = null; e != null; prev = e, e = e.next) {
294             if ((e.hash == hash) && e.key.equals(key)) {
295                 if (prev != null)
296                     prev.next = e.next;
297                 else
298                     tab[index] = e.next;
299                 count--;
300                 return e.value;
301             }
302         }
303         return null;
304     }
305 
306     /**
307      * Clears this hashtable so that it contains no keys.
308      */
309     public void clear() {
310         HashtableEntry tab[] = table;
311         for (int index = tab.length; --index >= 0;)
312             tab[index] = null;
313         count = 0;
314     }
315 
316     /**
317      * Returns a rather long string representation of this hashtable. Handy for
318      * debugging - leave it here!!!
319      */
320     public String toString() {
321         int i;
322         int max = size() - 1;
323         StringBuffer buf = new StringBuffer();
324         Enumeration k = keys();
325         Enumeration e = elements();
326         buf.append("{");
327 
328         for (i = 0; i <= max; i++) {
329             String s1 = k.nextElement().toString();
330             String s2 = e.nextElement().toString();
331             buf.append(s1 + "=" + s2);
332             if (i < max)
333                 buf.append(", ");
334         }
335         buf.append("}");
336         return buf.toString();
337     }
338 
339     /**
340      * A hashtable enumerator class. This class should remain opaque to the
341      * client. It will use the Enumeration interface.
342      */
343     class HashtableEnumerator implements Enumeration {
344         boolean keys;
345         int index;
346         HashtableEntry table[];
347         HashtableEntry entry;
348 
349         HashtableEnumerator(HashtableEntry table[], boolean keys) {
350             this.table = table;
351             this.keys = keys;
352             this.index = table.length;
353         }
354 
355         public boolean hasMoreElements() {
356             if (entry != null) {
357                 return true;
358             }
359             while (index-- > 0) {
360                 if ((entry = table[index]) != null) {
361                     return true;
362                 }
363             }
364             return false;
365         }
366 
367         public Object nextElement() {
368             if (entry == null) {
369                 while ((index-- > 0) && ((entry = table[index]) == null))
370                     ;
371             }
372             if (entry != null) {
373                 HashtableEntry e = entry;
374                 entry = e.next;
375                 return keys ? e.key : e.value;
376             }
377             return null;
378         }
379     }
380 
381 }
View Code
技术分享
 1 public class TestHash {
 2 
 3     public static void main(String[] args) {
 4         int length = 10000 * 20;
 5         MyHashTable map = new MyHashTable();
 6         for (int i = 0; i < length; i++) {
 7             map.put(new Person(i + "", i + ""), i + "");
 8         }
 9         map.printIndexCount();
10     }
11 }
View Code
技术分享
 1 /**
 2  * 具有相同身份证信息的人就是同一个人
 3  * 
 4  * @author Lucifer
 5  * 
 6  */
 7 public class Person {
 8 
 9     private String name;
10     private String identityCard;
11     private long age;
12 
13     public Person(String name, String identityCard) {
14         this.name = name;
15         this.setIdentityCard(identityCard);
16     }
17 
18     public String getName() {
19         return name;
20     }
21 
22     public void setName(String name) {
23         this.name = name;
24     }
25 
26     public String getIdentityCard() {
27         return identityCard;
28     }
29 
30     public void setIdentityCard(String identityCard) {
31         this.identityCard = identityCard;
32     }
33 
34     @Override
35     public int hashCode() {
36         return this.name.hashCode();
37     }
38     @Override
39     public boolean equals(Object obj) {
40         if (this == obj)
41             return true;
42         if (obj == null)
43             return false;
44         if (getClass() != obj.getClass())
45             return false;
46         Person other = (Person) obj;
47         if (age != other.age)
48             return false;
49         if (identityCard == null) {
50             if (other.identityCard != null)
51                 return false;
52         } else if (!identityCard.equals(other.identityCard))
53             return false;
54         if (name == null) {
55             if (other.name != null)
56                 return false;
57         } else if (!name.equals(other.name))
58             return false;
59         return true;
60     }
61 
62     public long getAge() {
63         return age;
64     }
65 
66     public void setAge(long age) {
67         this.age = age;
68     }
69 }
View Code

结果是,如果Person类重写了hashCode方法,hashtable的分块会更加细致。这样查找的效率就提高了。

我的理解有限,如果哪位大神看到了,请指点一二,非常感谢。

重写Object.hashCode如何提高hashtable的效率

标签:

原文地址:http://www.cnblogs.com/mayongsheng/p/4456378.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!