设为首页收藏本站Access中国

Office中国论坛/Access中国论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

返回列表 发新帖
查看: 3241|回复: 1
打印 上一主题 下一主题

【转载】Hashcode类,补全并简化代码:

[复制链接]
跳转到指定楼层
1#
发表于 2014-2-23 10:36:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

原理性文章:

http://www.cnblogs.com/abatei/archive/2009/06/23/1509790.html


  1. using System;
  2. public static class Prime
  3. {
  4.     public static readonly int[] primes = {
  5.             3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
  6.             1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
  7.             17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
  8.             187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
  9.             1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};
  10.     public static int NextPrime(int min)
  11.     {
  12.         // min>=0
  13.         int prime = 0;
  14.         for (int i = 0; i < primes.Length; i++) if (primes[i] >= min) break;
  15.         return prime;
  16.     }
  17. }
  18. public class Hashtable
  19. {
  20.     private struct bucket
  21.     {
  22.         public Object key;
  23.         public Object val;
  24.         public int hash_coll;
  25.     }
  26.     private bucket[] buckets;
  27.     private int count;
  28.     private int loadsize;
  29.     private float loadFactor;
  30.     public Hashtable() : this(0, 1.0f) { }
  31.     public Hashtable(int capacity, float loadFactor)
  32.     {
  33.         // loadFactor@[0.1f-1.0f]
  34.         this.loadFactor = loadFactor > 0.72f ? 0.72f : loadFactor;
  35.         double rawsize = capacity / this.loadFactor;
  36.         int hashsize = (rawsize > 11) ? Prime.NextPrime((int)rawsize) : 11;
  37.         buckets = new bucket[hashsize];
  38.         loadsize = (int)(this.loadFactor * hashsize);
  39.     }
  40.     public virtual void Add(Object key, Object value)
  41.     {
  42.         Insert(key, value, true);
  43.     }
  44.     private uint InitHash(Object key, int hashsize,out uint seed, out uint incr)
  45.     {
  46.         uint hashcode = (uint)GetHash(key) & 0x7FFFFFFF;
  47.         seed = (uint)hashcode; //h1
  48.         incr = (uint)(1 + (((seed >> 5) + 1) % ((uint)hashsize - 1)));//h2
  49.         return hashcode;
  50.     }
  51.     public virtual Object this[Object key] //索引器
  52.     {
  53.         get
  54.         {
  55.             uint seed; //h1
  56.             uint incr; //h2
  57.             uint hashcode = InitHash(key, buckets.Length,
  58.             out seed, out incr);
  59.             int ntry = 0; //用于表示h(key,i)中的i值
  60.             bucket b;
  61.             int bn = (int)(seed % (uint)buckets.Length); //h(key,0)
  62.             do
  63.             {
  64.                 b = buckets[bn];
  65.                 if (b.key == null) //b为无冲突空位时
  66.                 {  //找不到相应的键,返回空
  67.                     return null;
  68.                 }
  69.                 if (((b.hash_coll & 0x7FFFFFFF) == hashcode) &&
  70.                 KeyEquals(b.key, key))
  71.                 {   //查找成功
  72.                     return b.val;
  73.                 }
  74.                 bn = (int)(((long)bn + incr) %
  75.                 (uint)buckets.Length); //h(key+i)
  76.             } while (b.hash_coll < 0 && ++ntry < buckets.Length);
  77.             return null;
  78.         }
  79.         set
  80.         {
  81.             Insert(key, value, false);
  82.         }
  83.     }
  84.     private void expand()
  85.     {   
  86.         int rawsize = Prime.NextPrime(buckets.Length * 2);
  87.         rehash(rawsize);
  88.     }
  89.     private void rehash(int newsize)
  90.     {
  91.         bucket[] newBuckets = new bucket[newsize];
  92.         for (int nb = 0; nb < buckets.Length; nb++)
  93.         {
  94.             bucket oldb = buckets[nb];
  95.             if ((oldb.key != null) && (oldb.key != buckets))
  96.                 putEntry(newBuckets, oldb.key, oldb.val, oldb.hash_coll & 0x7FFFFFFF);
  97.         }
  98.         buckets = newBuckets;
  99.         loadsize = (int)(loadFactor * newsize);
  100.         return;
  101.     }
  102.     //在新数组内添加旧数组的一个元素
  103.     private void putEntry(bucket[] newBuckets, Object key,Object nvalue, int hashcode)
  104.     {
  105.         uint seed = (uint)hashcode; //h1
  106.         uint incr = (uint)(1 + (((seed >> 5) + 1) %
  107.         ((uint)newBuckets.Length - 1))); //h2
  108.         int bn = (int)(seed % (uint)newBuckets.Length);//哈希地址
  109.         do
  110.         {   //当前位置为有冲突空位或无冲突空位时都可添加新元素
  111.             if ((newBuckets[bn].key == null)||(newBuckets[bn].key == buckets))
  112.             {   //赋值
  113.                 newBuckets[bn].val = nvalue;
  114.                 newBuckets[bn].key = key;
  115.                 newBuckets[bn].hash_coll |= hashcode;
  116.                 return;
  117.             }
  118.             //当前位置已存在其他元素时
  119.             if (newBuckets[bn].hash_coll >= 0)
  120.                 newBuckets[bn].hash_coll |= unchecked((int)0x80000000);
  121.             //二度哈希h1(key)+h2(key)
  122.             bn = (int)(((long)bn + incr) % (uint)newBuckets.Length);
  123.         } while (true);
  124.     }
  125.     protected virtual int GetHash(Object key)
  126.     {   //获取哈希码
  127.         return key.GetHashCode();
  128.     }
  129.     protected virtual bool KeyEquals(Object item, Object key)
  130.     {   //用于判断两key是否相等
  131.         return item == null ? false : item.Equals(key);
  132.     }
  133.     //add:true添加,false修改
  134.     private void Insert(Object key, Object nvalue, bool add)
  135.     {
  136.         if (count >= loadsize) expand();
  137.         uint seed; //h1
  138.         uint incr; //h2
  139.         uint hashcode = InitHash(key, buckets.Length, out seed, out incr);
  140.         int ntry = 0; //用于表示h(key,i)中的i值
  141.         int emptySlotNumber = -1; //用于记录空位
  142.         int bn = (int)(seed % (uint)buckets.Length); //索引号
  143.         do
  144.         {   //如果是有冲突空位,需继续向后查找以确定是否存在相同的键
  145.             if (emptySlotNumber == -1 && (buckets[bn].key == buckets) &&(buckets[bn].hash_coll < 0))
  146.                 emptySlotNumber = bn;
  147.             if (buckets[bn].key == null) //确定没有重复键才添加
  148.             {
  149.                 if (emptySlotNumber != -1) //使用之前的空位
  150.                     bn = emptySlotNumber;
  151.                 buckets[bn].val = nvalue;
  152.                 buckets[bn].key = key;
  153.                 buckets[bn].hash_coll |= (int)hashcode;
  154.                 count++;
  155.                 return;
  156.             }
  157.             //找到重复键
  158.             if (((buckets[bn].hash_coll & 0x7FFFFFFF) == hashcode) && KeyEquals(buckets[bn].key, key))
  159.             {   //如果处于添加元素状态,则由于出现重复键而报错
  160.                 if (add) throw new ArgumentException("添加了重复的键值!");
  161.                 buckets[bn].val = nvalue; //修改批定键的元素
  162.                 return;
  163.             }
  164.             //存在冲突则置hash_coll的最高位为1
  165.             if (emptySlotNumber == -1)
  166.                 if (buckets[bn].hash_coll >= 0)
  167.                     buckets[bn].hash_coll |= unchecked((int)0x80000000);
  168.             bn = (int)(((long)bn + incr) % (uint)buckets.Length);//二度哈希
  169.         } while (++ntry < buckets.Length);
  170.         throw new InvalidOperationException("添加失败!");
  171.     }
  172.     public virtual void Remove(Object key) //移除一个元素
  173.     {
  174.         uint seed; //h1
  175.         uint incr; //h2
  176.         uint hashcode = InitHash(key, buckets.Length, out seed, out incr);
  177.         int ntry = 0; //h(key,i)中的i
  178.         bucket b;
  179.         int bn = (int)(seed % (uint)buckets.Length); //哈希地址
  180.         do
  181.         {
  182.             b = buckets[bn];
  183.             if (((b.hash_coll & 0x7FFFFFFF) == hashcode) && KeyEquals(b.key, key))
  184.             {   
  185.                 buckets[bn].hash_coll &= unchecked((int)0x80000000);
  186.                 if (buckets[bn].hash_coll != 0)
  187.                 {   //使key指向buckets
  188.                     buckets[bn].key = buckets;
  189.                 }
  190.                 else //原来不存在冲突
  191.                 {   //置key为空
  192.                     buckets[bn].key = null;
  193.                 }
  194.                 buckets[bn].val = null;  //释放相应的“值”。
  195.                 count--;
  196.                 return;
  197.             } //二度哈希
  198.             bn = (int)(((long)bn + incr) % (uint)buckets.Length);
  199.         } while (b.hash_coll < 0 && ++ntry < buckets.Length);
  200.     }
  201.     public override string ToString()
  202.     {
  203.         string s = string.Empty;
  204.         for (int i = 0; i < buckets.Length; i++)
  205.         {
  206.             if (buckets[i].key != null && buckets[i].key != buckets)
  207.             {   //不为空位时打印索引、键、值、hash_coll
  208.                 s += string.Format("{0,-5}{1,-8}{2,-8}{3,-8}/r/n",
  209.                 i.ToString(), buckets[i].key.ToString(),
  210.                 buckets[i].val.ToString(),
  211.                 buckets[i].hash_coll.ToString());
  212.             }
  213.             else
  214.             {   //是空位时则打印索引和hash_coll
  215.                 s += string.Format("{0,-21}{1,-8}/r/n", i.ToString(),
  216.                 buckets[i].hash_coll.ToString());
  217.             }
  218.         }
  219.         return s;
  220.     }
  221.     public virtual int Count
  222.     {   //获取元素个数
  223.         get { return count; }
  224.     }
  225. }
  226. class MyClass
  227. {
  228.     static void Main(string[] args)
  229.     {
  230.         Hashtable hs = new Hashtable();
  231.         hs.Add( 1, 3);
  232.         hs.Add( 2, 3);
  233.         hs.Add( 5, 3);
  234.         hs.Add( 4, 3);
  235.         Console.ReadKey();
  236.     }
  237. }
复制代码



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 分享淘帖 订阅订阅

点击这里给我发消息

2#
发表于 2014-2-23 10:41:38 | 只看该作者
谢谢分享,坐个沙发
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|站长邮箱|小黑屋|手机版|Office中国/Access中国 ( 粤ICP备10043721号-1 )  

GMT+8, 2024-5-7 14:41 , Processed in 0.085871 second(s), 25 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表