原理性文章: http://www.cnblogs.com/abatei/archive/2009/06/23/1509790.html using System; public static class Prime { public static readonly int[] primes = { 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369}; public static int NextPrime(int min) { // min>=0 int prime = 0; for (int i = 0; i < primes.Length; i++) if (primes[i] >= min) break; return prime; } } public class Hashtable { private struct bucket { public Object key; public Object val; public int hash_coll; } private bucket[] buckets; private int count; private int loadsize; private float loadFactor; public Hashtable() : this(0, 1.0f) { } public Hashtable(int capacity, float loadFactor) { // loadFactor@[0.1f-1.0f] this.loadFactor = loadFactor > 0.72f ? 0.72f : loadFactor; double rawsize = capacity / this.loadFactor; int hashsize = (rawsize > 11) ? Prime.NextPrime((int)rawsize) : 11; buckets = new bucket[hashsize]; loadsize = (int)(this.loadFactor * hashsize); } public virtual void Add(Object key, Object value) { Insert(key, value, true); } private uint InitHash(Object key, int hashsize,out uint seed, out uint incr) { uint hashcode = (uint)GetHash(key) & 0x7FFFFFFF; seed = (uint)hashcode; //h1 incr = (uint)(1 + (((seed >> 5) + 1) % ((uint)hashsize - 1)));//h2 return hashcode; } public virtual Object this[Object key] //索引器 { get { uint seed; //h1 uint incr; //h2 uint hashcode = InitHash(key, buckets.Length, out seed, out incr); int ntry = 0; //用于表示h(key,i)中的i值 bucket b; int bn = (int)(seed % (uint)buckets.Length); //h(key,0) do { b = buckets[bn]; if (b.key == null) //b为无冲突空位时 { //找不到相应的键,返回空 return null; } if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && KeyEquals(b.key, key)) { //查找成功 return b.val; } bn = (int)(((long)bn + incr) % (uint)buckets.Length); //h(key+i) } while (b.hash_coll < 0 && ++ntry < buckets.Length); return null; } set { Insert(key, value, false); } } private void expand() { int rawsize = Prime.NextPrime(buckets.Length * 2); rehash(rawsize); } private void rehash(int newsize) { bucket[] newBuckets = new bucket[newsize]; for (int nb = 0; nb < buckets.Length; nb++) { bucket oldb = buckets[nb]; if ((oldb.key != null) && (oldb.key != buckets)) putEntry(newBuckets, oldb.key, oldb.val, oldb.hash_coll & 0x7FFFFFFF); } buckets = newBuckets; loadsize = (int)(loadFactor * newsize); return; } //在新数组内添加旧数组的一个元素 private void putEntry(bucket[] newBuckets, Object key,Object nvalue, int hashcode) { uint seed = (uint)hashcode; //h1 uint incr = (uint)(1 + (((seed >> 5) + 1) % ((uint)newBuckets.Length - 1))); //h2 int bn = (int)(seed % (uint)newBuckets.Length);//哈希地址 do { //当前位置为有冲突空位或无冲突空位时都可添加新元素 if ((newBuckets[bn].key == null)||(newBuckets[bn].key == buckets)) { //赋值 newBuckets[bn].val = nvalue; newBuckets[bn].key = key; newBuckets[bn].hash_coll |= hashcode; return; } //当前位置已存在其他元素时 if (newBuckets[bn].hash_coll >= 0) newBuckets[bn].hash_coll |= unchecked((int)0x80000000); //二度哈希h1(key)+h2(key) bn = (int)(((long)bn + incr) % (uint)newBuckets.Length); } while (true); } protected virtual int GetHash(Object key) { //获取哈希码 return key.GetHashCode(); } protected virtual bool KeyEquals(Object item, Object key) { //用于判断两key是否相等 return item == null ? false : item.Equals(key); } //add:true添加,false修改 private void Insert(Object key, Object nvalue, bool add) { if (count >= loadsize) expand(); uint seed; //h1 uint incr; //h2 uint hashcode = InitHash(key, buckets.Length, out seed, out incr); int ntry = 0; //用于表示h(key,i)中的i值 int emptySlotNumber = -1; //用于记录空位 int bn = (int)(seed % (uint)buckets.Length); //索引号 do { //如果是有冲突空位,需继续向后查找以确定是否存在相同的键 if (emptySlotNumber == -1 && (buckets[bn].key == buckets) &&(buckets[bn].hash_coll < 0)) emptySlotNumber = bn; if (buckets[bn].key == null) //确定没有重复键才添加 { if (emptySlotNumber != -1) //使用之前的空位 bn = emptySlotNumber; buckets[bn].val = nvalue; buckets[bn].key = key; buckets[bn].hash_coll |= (int)hashcode; count++; return; } //找到重复键 if (((buckets[bn].hash_coll & 0x7FFFFFFF) == hashcode) && KeyEquals(buckets[bn].key, key)) { //如果处于添加元素状态,则由于出现重复键而报错 if (add) throw new ArgumentException("添加了重复的键值!"); buckets[bn].val = nvalue; //修改批定键的元素 return; } //存在冲突则置hash_coll的最高位为1 if (emptySlotNumber == -1) if (buckets[bn].hash_coll >= 0) buckets[bn].hash_coll |= unchecked((int)0x80000000); bn = (int)(((long)bn + incr) % (uint)buckets.Length);//二度哈希 } while (++ntry < buckets.Length); throw new InvalidOperationException("添加失败!"); } public virtual void Remove(Object key) //移除一个元素 { uint seed; //h1 uint incr; //h2 uint hashcode = InitHash(key, buckets.Length, out seed, out incr); int ntry = 0; //h(key,i)中的i bucket b; int bn = (int)(seed % (uint)buckets.Length); //哈希地址 do { b = buckets[bn]; if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && KeyEquals(b.key, key)) { buckets[bn].hash_coll &= unchecked((int)0x80000000); if (buckets[bn].hash_coll != 0) { //使key指向buckets buckets[bn].key = buckets; } else //原来不存在冲突 { //置key为空 buckets[bn].key = null; } buckets[bn].val = null; //释放相应的“值”。 count--; return; } //二度哈希 bn = (int)(((long)bn + incr) % (uint)buckets.Length); } while (b.hash_coll < 0 && ++ntry < buckets.Length); } public override string ToString() { string s = string.Empty; for (int i = 0; i < buckets.Length; i++) { if (buckets[i].key != null && buckets[i].key != buckets) { //不为空位时打印索引、键、值、hash_coll s += string.Format("{0,-5}{1,-8}{2,-8}{3,-8}/r/n", i.ToString(), buckets[i].key.ToString(), buckets[i].val.ToString(), buckets[i].hash_coll.ToString()); } else { //是空位时则打印索引和hash_coll s += string.Format("{0,-21}{1,-8}/r/n", i.ToString(), buckets[i].hash_coll.ToString()); } } return s; } public virtual int Count { //获取元素个数 get { return count; } } } class MyClass { static void Main(string[] args) { Hashtable hs = new Hashtable(); hs.Add( 1, 3); hs.Add( 2, 3); hs.Add( 5, 3); hs.Add( 4, 3); Console.ReadKey(); } }