HashTable的实现

 

为了实现高效访问一个集合中的元素,Mpr中实现了Hash Table,其结构如下图所示

图片

 

类的简单描述:

MprHashTable是存储和管理Hash内容的类,MprHashEntry是HashTable的一项,有三个派生类MprStringHashEntry、MprStaticHashEntry和MprObjectHashEntry

 

个各类的详细描述:

MprHashTable类

如下图所示,MprHashTable类使用链表来存储存在冲突的元素集,但是这只是MprHashTable类的简单结构

图片

成员变量

   MprList   *buckets;
   int    size;
   int    count;

正如我在MprList实现那章所描述的一样,类MprList在这里的目的是用于存储MprLink(或其子类但不包括MprList)类型的指针,在这里是MprHashEntry或其子类MprStringHashEntry、MprStaticHashEntry和MprObjectHashEntry

成员函数

插入操作:int MprHashTable::insert(MprHashEntry *value)

实例:MprHashTable hashTable, MprHashEntry* entryPtr1, MprHashEntry* entryPtr2,entryPtr1和entryPtr2指向两个MprHashEntry的实例

1.在执行插入操作之前

图片

2.entryPtr1 = new MprHashEntry(“item1”);

    hashTable.insert(entryPtr1);

在这步操作之后,hashTable所做的事情是通过调用lookupInner查看entryPtr1是否在hashTable中,并返回buckets[i]的地址给bp和"item1"在bp指向的链表中的位置给ep,如果ep不等于NUll,则将entryPtr1插入到ep之后,然后删除ep。否则将entryPtr1插入到对应项。假设"item1"对应的hash值为0,即i = 0。
图片

3.entryPtr2 = new MprHashEntry(“item2”);

    hashTable.insert(entryPtr2);

3.1如果"item2"的hash值和"item1"的hash值不同,假设这时候的hash值为2,即i = 2

图片

3.2如果"item2"的hash值和"item1"的hash值相同

图片

3.3 再一次执行如下操作

 entryPtr3 = new MprHashEntry(“item2”);

    hashTable.insert(entryPtr3);

图片

在插入entryPtr3之前,首先通过通过hash函数计算出"Item2"对应的hash值,然后将entryPtr3插入到entryPtr2的后面,最后删除entryPtr2

 

 MprList   *bp;
 MprHashEntry  *ep;

 if ((ep = lookupInner(value->key, &bp)) != 0) {
    //
    // Already exists. Delete the old and insert the new. Insert
    // first to make sure we get the right position
    //
    ep->insertAfter(value);
    value->bucket = bp;
    bp->remove(ep);
    delete ep;
    return 0;
 }
 //
 // New entry
 //
 bp->insert(value);
 value->bucket = bp;
 count++;
 return 0;

 

删除操作1:int MprHashTable::remove(char *key)
通过lookupInner函数查找key对应的bucket[i]和该链表上的对应item

 MprList   *bp;
 MprHashEntry  *ep;

 if ((ep = lookupInner(key, &bp)) == 0) {
    return MPR_ERR_NOT_FOUND;
 }
 bp->remove(ep);
 count--;
 return 0;

 

删除操作2:int MprHashTable::remove(MprHashEntry *ep)

 ep->bucket->remove(ep);
 count--;
 return 0;

 

删除hashTable中的所有元素:int MprHashTable::removeAll()

依次遍历所有的bucket[i],删除该队列中所有的元素

 

查找:MprHashEntry *MprHashTable::lookup(char *key)

   MprHashEntry *MprHashTable::lookupInner(char *key, MprList **bucket)

在这里我们只讲第二个函数,该函数的操作过程是:首先通过通过hash函数将key值映射到i上,通过buckets[i]查找到对应的MprList的入口点,再依次查找MprList,将其元素的key值和目标元素的key值进行比较,直到找到对应的item,则返回该item;否则返回NULL。

 MprList   *bp;
 MprHashEntry *ep;
 int    index, rc;

 mprAssert(key);

 index = hashIndex(key);
 bp = &buckets[index];
 ep = (MprHashEntry*) bp->getFirst();
 if (bucket) {
    *bucket = bp;
 }

 while (ep) {
    rc = strcmp(ep->key, key);
    if (rc == 0) {
       return ep;
    }
    ep = (MprHashEntry*) bp->getNext(ep);
 }
 return 0;

得到第一个元素:MprHashEntry *MprHashTable::getFirst()

从buckets[0]由左向右,由上向下查找,如果找到有一个链表中的元素不为NULL,则返回


得到下一个元素:MprHashEntry *MprHashTable::getNext(MprHashEntry *ep)
从ep开始由左向右,由上向下查找,如果找到有一个链表中的元素不为NULL,则返回

 

hash映射:

int MprHashTable::hashIndex(char *key)
{
   uint  sum;

   sum = 0;
   while (*key) {
      sum += (sum * 33) + *key++;
   }

   return sum % size;
}

这个函数的选取特别重要,因为一个好的hash函数可以减少冲突,使各个bucket内的内容比较均匀。

 

MprHashEntry、MprStringHashEntry、MprStaticHashEntry和MprObjectHashEntry这四个类都比较简单,这里就不描述了,后两个类是从MprHashEntry继承,他们和MprHashEntry的不同时由于他们除了有key值还有对应的value值。其中MprStringHashEntry和MprStaticHashEntry的区别是MprStringHashEntry中的value是一个可以修改的MprStr类型,而MprStaticHashEntry中的value是char*类型,我们知道该类型指向的指针式不能够被修改的。而MprObjectHashEntry是定义在编译宏PERHAPS下面的,其定义和MprStaticHashEntry是完全一样。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值