哈希表的实现

来源:互联网 发布:腾讯软件大全 编辑:程序博客网 时间:2024/05/18 18:04

 using System;2   public class Hashtable3   {4       private struct bucket5       {6           public Object key; //7           public Object val; //8           public int hash_coll; //哈希码9       }10      private bucket[] buckets; //存储哈希表数据的数组(数据桶)11      private int count; //元素个数12      private int loadsize; //当前允许存储的元素个数13      private float loadFactor; //填充因子14      //默认构造方法15      public Hashtable() : this(01.0f) { }16      //指定容量的构造方法17      public Hashtable(int capacity, float loadFactor)18      {19          if (!(loadFactor >= 0.1f && loadFactor <= 1.0f))20              throw new ArgumentOutOfRangeException(21                  "填充因子必须在0.1~1之间");22          this.loadFactor = loadFactor > 0.72f ? 0.72f : loadFactor;23          //根据容量计算表长24          double rawsize = capacity / this.loadFactor;25          int hashsize = (rawsize > 11) ? //表长为大于11的素数26              HashHelpers.GetPrime((int)rawsize) : 11;27          buckets = new bucket[hashsize]; //初始化容器28          loadsize = (int)(this.loadFactor * hashsize);29      }30      public virtual void Add(Object key, Object value) //添加31      {   32          Insert(key, value, true);33      }34      //哈希码初始化35      private uint InitHash(Object key,int hashsize,36          out uint seed,out uint incr)37      {38          uint hashcode = (uint)GetHash(key) & 0x7FFFFFFF//取绝对值39          seed = (uint)hashcode; //h140          incr = (uint)(1 + (((seed >> 5)+1) % ((uint)hashsize-1)));//h241          return hashcode; //返回哈希码42      }43      public virtual Object this[Object key] //索引器44      {45          get46          {47              uint seed; //h148              uint incr; //h249              uint hashcode = InitHash(key, buckets.Length, 50                  out seed, out incr);51              int ntry = 0//用于表示h(key,i)中的i值52              bucket b;53              int bn = (int)(seed % (uint)buckets.Length); //h(key,0)54              do55              {56                  b = buckets[bn]; 57                  if (b.key == null//b为无冲突空位时58                  {  //找不到相应的键,返回空59                      return null;60                  }61                  if (((b.hash_coll & 0x7FFFFFFF) == hashcode) &&62                      KeyEquals(b.key, key))63                  {   //查找成功64                      return b.val;65                  }66                  bn = (int)(((long)bn + incr) % 67                      (uint)buckets.Length); //h(key+i)68              } while (b.hash_coll < 0 && ++ntry < buckets.Length);69              return null;70          }71          set72          {73              Insert(key, value, false);74          }75      }76      private void expand() //扩容77      {   //使新的容量为旧容量的近似两倍78          int rawsize = HashHelpers.GetPrime(buckets.Length * 2); 79          rehash(rawsize);80      }81      private void rehash(int newsize) //按新容量扩容82      {83          bucket[] newBuckets = new bucket[newsize];84          for (int nb = 0; nb < buckets.Length; nb++)85          {86              bucket oldb = buckets[nb];87              if ((oldb.key != null) && (oldb.key != buckets))88              {89                  putEntry(newBuckets, oldb.key, oldb.val, 90                      oldb.hash_coll & 0x7FFFFFFF);91              }92          }93          buckets = newBuckets;94          loadsize = (int)(loadFactor * newsize);95          return;96      }97      //在新数组内添加旧数组的一个元素98      private void putEntry(bucket[] newBuckets, Object key, 99          Object nvalue, int hashcode)100     {101         uint seed = (uint)hashcode; //h1102         uint incr = (uint)(1 + (((seed >> 5) + 1) % 103             ((uint)newBuckets.Length - 1))); //h2104         int bn = (int)(seed % (uint)newBuckets.Length);//哈希地址105         do106         {   //当前位置为有冲突空位或无冲突空位时都可添加新元素107             if ((newBuckets[bn].key == null) || 108                 (newBuckets[bn].key == buckets))109             {   //赋值110                 newBuckets[bn].val = nvalue;111                 newBuckets[bn].key = key;112                 newBuckets[bn].hash_coll |= hashcode;113                 return;114             }115             //当前位置已存在其他元素时116             if (newBuckets[bn].hash_coll >= 0)117             {   //置hash_coll的高位为1118                 newBuckets[bn].hash_coll |= 119                     unchecked((int)0x80000000);120             }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时用作添加元素,当add为false时用作修改元素值134     private void Insert(Object key, Object nvalue, bool add)135     {   //如果超过允许存放元素个数的上限则扩容136         if (count >= loadsize)137         {   138             expand();139         }140         uint seed; //h1141         uint incr; //h2142         uint hashcode = InitHash(key, buckets.Length,out seed, out incr);143         int ntry = 0//用于表示h(key,i)中的i值144         int emptySlotNumber = -1//用于记录空位145         int bn = (int)(seed % (uint)buckets.Length); //索引号146         do147         {   //如果是有冲突空位,需继续向后查找以确定是否存在相同的键148             if (emptySlotNumber == -1 && (buckets[bn].key == buckets) &&149                 (buckets[bn].hash_coll < 0))150             {151                 emptySlotNumber = bn;152             }153             if (buckets[bn].key == null//确定没有重复键才添加154             {155                 if (emptySlotNumber != -1//使用之前的空位156                     bn = emptySlotNumber;157                 buckets[bn].val = nvalue;158                 buckets[bn].key = key;159                 buckets[bn].hash_coll |= (int)hashcode;160                 count++;161                 return;162             }163             //找到重复键164             if (((buckets[bn].hash_coll & 0x7FFFFFFF)==hashcode) &&165                 KeyEquals(buckets[bn].key, key))166             {   //如果处于添加元素状态,则由于出现重复键而报错167                 if (add)168                 {169                     throw new ArgumentException("添加了重复的键值!");170                 }171                 buckets[bn].val = nvalue; //修改批定键的元素172                 return;173             }174             //存在冲突则置hash_coll的最高位为1175             if (emptySlotNumber == -1)176             {177                 if (buckets[bn].hash_coll >= 0)178                 {179                     buckets[bn].hash_coll |= unchecked((int)0x80000000);180                 }181             }182             bn = (int)(((long)bn + incr) % (uint)buckets.Length);//二度哈希183         } while (++ntry < buckets.Length);184         throw new InvalidOperationException("添加失败!");185     }186     public virtual void Remove(Object key) //移除一个元素187     {188         uint seed; //h1189         uint incr; //h2190         uint hashcode = InitHash(key, buckets.Length,out seed, out incr);191         int ntry = 0//h(key,i)中的i192         bucket b;193         int bn = (int)(seed % (uint)buckets.Length); //哈希地址194         do195         {196             b = buckets[bn];197             if (((b.hash_coll & 0x7FFFFFFF) == hashcode) &&198                 KeyEquals(b.key, key)) //如果找到相应的键值199             {   //保留最高位,其余清0200                 buckets[bn].hash_coll &= unchecked((int)0x80000000);201                 if (buckets[bn].hash_coll != 0//如果原来存在冲突202                 {   //使key指向buckets203                     buckets[bn].key = buckets;204                 }205                 else //原来不存在冲突206                 {   //置key为空207                     buckets[bn].key = null;208                 }209                 buckets[bn].val = null;  //释放相应的“值”。210                 count--;211                 return;212             } //二度哈希213             bn = (int)(((long)bn + incr) % (uint)buckets.Length);214         } while (b.hash_coll < 0 && ++ntry < buckets.Length);215     }216     public override string ToString()217     {218         string s = string.Empty;219         for (int i = 0; i < buckets.Length; i++)220         {221             if (buckets[i].key != null && buckets[i].key != buckets)222             {   //不为空位时打印索引、键、值、hash_coll223                 s += string.Format("{0,-5}{1,-8}{2,-8}{3,-8}\r\n",224                     i.ToString(), buckets[i].key.ToString(),225                     buckets[i].val.ToString(), 226                     buckets[i].hash_coll.ToString());227             }228             else229             {   //是空位时则打印索引和hash_coll230                 s += string.Format("{0,-21}{1,-8}\r\n", i.ToString(),231                     buckets[i].hash_coll.ToString());232             }233         }234         return s;235     }236     public virtual int Count //属性237     {   //获取元素个数238         get { return count; }239     }240 }

 

原创粉丝点击