zoukankan      html  css  js  c++  java
  • 重写Object.hashCode如何提高hashtable的效率

    首先,我个人对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的分块会更加细致。这样查找的效率就提高了。

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

  • 相关阅读:
    网友谈:Dictionary.ContainsKey和List.BinarySearch哪个效率高
    C# WinForm 中在窗口标题栏上加按钮
    将Txt文件转换成dataset[原创]
    四个常见的排序算法[原创]
    改版后的groupbox[原创]
    转 五种提高 SQL 性能的方法
    转 牢记!SQL Server数据库开发的二十一条军规(SQL收藏)
    源码详解Java的反射机制
    java多线程采集+线程同步
    jQgrid API
  • 原文地址:https://www.cnblogs.com/mayongsheng/p/4456378.html
Copyright © 2011-2022 走看看