Hash Table

     刚到学校的时候把宽带的密码搞忘了,跑了两次新华公园的电信这才可以上了。前几天因为忙着做一个定单的项目,没有抽时间来看数据结构。到了今天才把软件的大体框架完成,准备拿过去给客户看了。刚才抽了点时间看了下Hash Table,现在就把看的东西记下来。。。

   Hash Table这种数据结构比以前见到的Binary Tree的搜索,插入,删除所需要的时间还要短,时间复杂度逼近O(1)。在看到书上这句话的时候,我兴奋不已,世上居然有如此好的事?再往下看,究竟是怎么一回事呢。原来Hash Table有一个自己的Hash Function(Hash函数),Hash Table是把所有的数据放入一个数组中,然后通过把数据的key传给Hash Func,Hash Func会算出一个全局唯一的值(理论上),也就是这个数据在数组中的Index,然后找到这个数据。插入和删除就不多说了,能找到这个数据的位置还怕插入,删除不了?这样一来,我对Hash Table的疑问就转到了Hash Func身上。“一个Hash Func能把所有可能传进来的值算出一个唯一值。”太神气了吧,我自己不是学数学的,不知道哪个牛人能写出这样一个Func。看到这,我就觉得有点糊涂,头脑中太多的问号了,什么叫做传进来的可能的值,什么算法能算出唯一的值?我就继续往下面看。这时,书上举了个例子:把英文中的单词存放到一个Hash Table中(假设英文单词最多由10个字母组成),要求当然是插入,删除的时候要非常的快。书上给了一个比较喊的方法,就是把字母进行编码,空格-0,A-1,B-2.......Z-26.这样每个可能的单词就有了自己的一个唯一的key,比如a就可以用0000000001来表示。有了Key,怎么来实现一个Hash Func,能让传进来的数得到一个唯一的值呢?当然直接用key来做数组的Index是愚蠢的,首先,不可能定义一个如此之大的数组,大小是7,000,000,000,000,再来像zzzzzzzzzz这样的根本就不是单词,也就造成了空间的大量浪费。有个可行的方法就是把这十位数加起来,这样就要一个26*10=260的存储空间,但是事实上,总共有50,000个单词,这样发生冲突的Key就会有很多很多。那么如何确定数组的大小呢?如果有50,000个单词,那么就定义一个有100,000个元素的数组(为了以后可以插入新的元素),那么怎么再通过一个Hash Func把一个有7,000,000,000,000个可能的数Hash到一个100,000的数组中呢,有个最简单的方法就是用%,smallNumber = largeNumber % smallRange;所有得到的smallNumber的大小都会在smallRange之内。

  好了,Hash Table的基本原理就是这样,把一群要存储的数据放到一个数组中,每个数据单元都有个唯一的key,Hash Table在通过Hash Func把这个Key转变成一个数组的下标,这个数组的下标在理论上是唯一的,实际上并不是,有个很简单,但又很实用的Hash Func就是%,规则就是Index = Key的范围%数组的大小。

  刚才已经提到,其实Hash Func算出的值肯定是有冲突的,不同的Key可能得到相同值,这个时候就要有一套处理冲突的办法,这些办法可以分为两大类,一类是开放式寻址,一类是用Linked List来作为存储的单元。开放式寻址又有线形探针,2次方探针和reHash法。其中reHash法是最为有效的了。下面就以reHash法来完成一个Hash Table

public class Item
{
         public long data;
         public Item(long data)
         {
          this.data = data;
 }
}
public class HashTable
{
         private Item[] items;
         public int size;
         public Item nonItem;
         public HashTable(int size)
         {
                  this.size = size;
                  items = new Item[size];
                  nonItem = new Item(-1);
         }
         public int hashFunc(int key)
         {
                  int result = key % size;
                  return result;
         }
         public int reHashFunc(int key)
         {
                  int result = 5 - (key % 5);
                  return result;
         }
         public Item find(int key)
         {
                  int hashVal = hashFunc(key);
                  int hashStep = reHashFunc(.key);
                  if(items[hashVal]!=hashVal)
                  {
                           while(items[hashVal]!=null)
                           {
                                    if(items[hashVal]==key)
                                             return items[hashVal];
                                    hashVal += hashStep;
                                    hashVal %= size;//超出数组范围时,返回到数组的前端
                           }
                           return null
                  }
         }
         public void Insert(int item)
         {
                  int hashVal = hashFunc(key);
                  int hashStep = hashFunc(key);
                  while(items[hashVal]!=null&&items[hashVal].data!=-1)
                  {
                           hashVal += hashStep;
                           hashVal %= sizt;
                  }
                  items[hahsVal] = item;
         }
         public DataItem delete(int key) // delete a DataItem
         {
                  int hashVal = hashFunc(key); // hash the key
                  int stepSize = rehashFunc(key); // get step size
                  while(hashArray[hashVal] != null) // until empty cell
                  {
                           if(hashArray[hashVal].iData == key)//is correct hashVal?
                           {
                                    DataItem temp = hashArray[hashVal]; // save item
                                    hashArray[hashVal] = nonItem; // delete item
                                    return temp; // return item
                           }
                           hashVal += stepSize; // add the step
                           hashVal %= arraySize; // for wraparound
                  }
                  return null; // can't find item
         } // end delete()
}

Plus:

1.对reHashFunc()做个补充

  • 首先reHash肯定不可能和第1个HashFunc()一样,不然同样的Key会依然有同样的步长,就失去了reHashFuc的意义
  • reHashFunc不能得到一个为0的数,不然步长为0就不能进行移动了,算法会进入一个死循环,这样的reHashFunc比较实用stepSize = constant - (key % constant)


2.数组的大小要是一个质数:为了防止死循环,假设数组大小为15,初始的Hash值为0,补长为5,这样会进入到一个0,5,10的死循环,就不能去寻找其他的元素。

 

 


 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值