前注:本文不是讲解Java类库的Hashtable实现原理,而是根据计算机哈希表原理自己实现的一个Hashtable。

HashTable内部是用数组存放一个(Key-Value pair)键值对的引用,其原理是根据Key的hashCode来计算出数组下标。因为存放位置是直接计算出来,不需要遍历数据结构,这使得hash table具有快速增删查改的优势。下面介绍HashTable的实现步骤:

  • 取得Key的hashCode。

  通过Eclipse等工具可以轻松的复写Object的hashCode方法,生成的hashCode是不会有重复值的。

  • 将hashCode与地址映射(压缩地址):

  但是,Hashtable内部是用一个数组来存储Key-Value对的,数组容量有限,本文中设置数组容量为10。那么现在的问题就是如何将hashCode和数组地址相对应?一个简单的方法就是对hashCode取模运算(hashCode%10)。这样就可以将hashCode与数组地址做映射(多对一)。同时注意,hashCode可能为负数,而数组的下标不能为负数,所以在映射的时候需要处理一下。

1 int hashCode =  Math.abs(key.hashCode())% this.maxSize;
  • 解决hashCode重复问题:

上文已经说过,数组容量为10,当我们在将hashCode映射为数组下标的时候,肯定会遇到有重复的情况。比如hashCode为21和31,分别对他们取模运算,结果都是1,也就是说这两个hashCode对应数组的下标都是1.那么第一个元素添加上去后,再添加第二个元素,则新元素会覆盖之前的元素。这时,如果我们想后面添加的重复地址元素也能添加上去,只能将其放在其它位置。这时,我们可以将新元素放在改地址的下一位,如果下一位已经有元素,那么就继续往后找,直到找到空位为止(其实这个过程有些边界条件需要考虑,比如找到数组末尾后应跳到数组开头继续找。以及数组已经满了,找遍数组都找不到合适的位置,就应该提示该数组已满,不能插入)。 

现在既然解决了上面的问题,也就是说每个元素都能在数组中找到合适的位置(除非数组已满)。那么可以根据这个算法实现数组的增删查改。下面是Hashtable的实现代码:

  1 package org.lyk.impl;
  2 
  3 public class HashTable<K, V>
  4 {
  5     /**
  6      * Key-Value pair 存放键值对
  7      * @author liuyuank
  8      *
  9      */
 10     private class KeyValue
 11     {
 12         K key;
 13         V value;
 14 
 15         private KeyValue(K key, V value)
 16         {
 17             this.key = key;
 18             this.value = value;
 19         }
 20 
 21         public K getKey()
 22         {
 23             return key;
 24         }
 25 
 26         public void setKey(K key)
 27         {
 28             this.key = key;
 29         }
 30 
 31         public V getValue()
 32         {
 33             return value;
 34         }
 35 
 36         public void setValue(V value)
 37         {
 38             this.value = value;
 39         }
 40 
 41     }
 42 
 43     private Object[] table;
 44     private int maxSize = 10;
 45     private int currentAmmount = 0;
 46 
 47     public HashTable()
 48     {
 49         this.table = new Object[this.maxSize];
 50     }
 51 
 52     public HashTable(int maxSize) throws Exception
 53     {
 54         if (0 == maxSize || maxSize < 0 || maxSize > 100)
 55         {
 56             throw new Exception("table容量非法!");
 57         }
 58 
 59         this.maxSize = maxSize;
 60         this.table = new Info[maxSize];
 61     }
 62 
 63     /**
 64      * 增加一个键值对
 65      * @param key
 66      * @param value
 67      */
 68     public void add(K key, V value)
 69     { 
 70         //将hashCode映射到数组下标
 71         int hashCode =  Math.abs(key.hashCode())% this.maxSize;
 72         
 73         //将元素插入到数组中,如果该位置已经被占用,则循环查找下一个位置,直到找到合适的位置,或发现数组已满,退出循环
 74         while (this.table[hashCode] != null
 75                 && (this.currentAmmount < this.maxSize))
 76         {
 77             hashCode++;
 78             hashCode = hashCode % this.maxSize;
 79         }
 80 
 81         if (this.currentAmmount == this.maxSize)
 82         {
 83             //数组已满
 84             System.out.println("Hash table 已满");
 85         } else
 86         {
 87             //找到合适位置
 88             this.table[hashCode] = new KeyValue(key, value); 
 89             this.currentAmmount++;
 90         }
 91     }
 92 
 93     /**
 94      * 与add方法同样的算法,根据key值找到数组中元素,然后将改元素设置为null
 95      * @param key
 96      * @return
 97      */
 98     public boolean remove(K key)
 99     {
100         int hashCode = Math.abs(key.hashCode()) % this.maxSize;
101         int count = 0;
102         while (this.table[hashCode] != null && count < this.maxSize)
103         {
104             if (((KeyValue) this.table[hashCode]).getKey().equals(key))
105             {
106                 this.table[hashCode] = null;
107                 return true;
108             }
109             count++;
110             hashCode++;
111             hashCode = hashCode%this.maxSize;
112         }
113 
114         return false;
115     }
116 
117     public V get(K key)
118     {
119         int hashCode = Math.abs(key.hashCode()) % this.maxSize;
120         int count = 0;
121         while (this.table[hashCode] != null && count < this.maxSize)
122         {
123             if (key.equals(((KeyValue)this.table[hashCode]).getKey()))
124                 return ((KeyValue) this.table[hashCode]).getValue();
125             
126             hashCode++;
127             count++;
128             hashCode = hashCode%this.maxSize;
129         }
130         return null;
131     }
132 
133     public boolean contains(K key)
134     {
135         if (this.get(key) != null)
136         {
137             return true;
138         } else
139         {
140             return false;
141         }
142     }
143     
144     public void replace(K key, V value)
145     {
146         KeyValue kv = this.find(key);
147         if(kv != null)
148         { 
149             kv.setValue(value);
150         }
151     }
152     
153     private KeyValue find(K key)
154     {
155         int hashCode = Math.abs(key.hashCode()) % this.maxSize;
156         int count = 0;
157         while (this.table[hashCode] != null && count < this.maxSize)
158         {
159             if (key.equals(((KeyValue)this.table[hashCode]).getKey()))
160                 return ((KeyValue) this.table[hashCode]);
161             
162             hashCode++;
163             count++;
164             hashCode = hashCode%this.maxSize;
165         }
166         return null;
167     }
168 }
HashTable实现

相关文章:

  • 2021-11-22
  • 2022-12-23
  • 2022-12-23
  • 2021-10-17
  • 2021-11-26
  • 2021-08-02
  • 2022-12-23
  • 2022-02-09
猜你喜欢
  • 2022-12-23
  • 2021-07-22
  • 2022-12-23
  • 2021-12-16
  • 2021-07-07
  • 2021-07-09
  • 2021-07-12
相关资源
相似解决方案