srilm 阅读文档4

这篇博客详细介绍了C++中LHash模板类的实现,包括LHashBody、LHash和LHashIter三个类。LHashBody存储哈希表数据,LHash提供映射操作,LHashIter实现迭代器功能。博客讲解了构造函数、析构函数、赋值操作、查找、插入和删除等核心方法,特别是插入和删除操作中开放地址线性探测解决冲突的策略。此外,还提到了LHashIter的构造函数、排序和迭代功能。
摘要由CSDN通过智能技术生成

LHash.h LHash.cc
文档作者:jianzhu
创立时间:08.08.23

--------------------------------------
1、基本类
-------------------------------------- 
    这两个文件主要以模板方式定义了三个类:哈希体(LHashBody)、哈希(LHash),
以及哈希迭代器(LHashIter)类。这三个类符合映射类型的接口方式。
    其中哈希体类,定义了哈希表中的数据成员的类型。哈希表类以哈希方式定义
了映射类型的相关函数,而哈希迭代器类则以迭代器的设计模式方式定义了迭代哈
希表中数据元素的相关函数。
    类的结构关系图(LHash.bmp)
LHashBody类
    该类定义了LHash类的数据成员
    a) unsigned maxBits:LHASH_MAXBIT_NBITS;
       哈希值的位数
    b) unsigned nEntries:LHASH_MAXENTRY_NBITS;
       哈希表中的“键->值”对数
    c) MapEntry<KeyT,DataT> data[1];
       保存“键->值”对的单元
       
LHash类
    该类以哈希方式定义了映射类型的相关关函数
    a) 构造函数
    b) 析构函数
    c) 赋值函数
    d) 拷贝构造函数
    e) 查找函数
    f) 插入函数
    g) 删除函数
    h) 清空函数
    i) size函数
    j) getInternalKey函数
    k) memStats函数
LHashIter类
    该类以迭代器方式定义了遍历LHash哈希表需要的相关函数
    a) 构造函数
    b) 析构函数
    c) init函数
    d) next函数
--------------------------------------
2、函数功能解释
--------------------------------------
LHash类
a) 构造函数
<src>
0  template <class KeyT, class DataT>
1  LHash<KeyT,DataT>::LHash(unsigned size)
2  : body(0)
3  {
4    if (size != 0) {
5      /*
6      * determine actual initial size
7      */
8      alloc(roundSize(size));
9    }
10 }
</src>
    功能:用于对当前对象进行初始化,同时分配相应的内存空间。
    
    细解:第8行首先调用roundSize函数确定对应当前初始化空间的哈希表大小。
    然后将哈希表大小传入alloc函数,以分配相应的空间。
      roundSize函数
   <src>
   0   static inline unsigned
   1   roundSize(unsigned size)
   2   {
   3    if (size < hashSize(minHashBits)) {
   4      return size;
   5    } 
   6    else {
   7      return (unsigned)((size + 1)/ fillRatio);
   8    }
   9   }
   </src>
   
      第3行判断当前要分配的空间大小是否小于8,若小于8则直接返回size。
      否则运行第7行。
      第7行将空间大小加1,同时除以哈希表的转载比例系数,并将运算后得到
      的大小返回。
      
   alloc函数
   0  template <class KeyT, class DataT>
   1  void
   2  LHash<KeyT,DataT>::alloc(unsigned size)
   3  {
   4    unsigned maxBits, maxEntries;
   5    unsigned i;
   6  
   7    /*
   8     * round up to power of two
   9    */
   10   maxBits = 0;
   11   while (hashSize(maxBits) < size) {
   12     assert(maxBits < LHash_maxBitLimit);
   13     maxBits++;
   14   }
   15   maxEntries = hashSize(maxBits);
   16
   17   body = (LHashBody<KeyT,DataT> *)malloc(sizeof(*BODY(body)) +
   18         (maxEntries - 1) * sizeof(BODY(body)->data[0]));
   19   assert(body != 0);
   20
   21   BODY(body)->maxBits = maxBits;
   22   BODY(body)->nEntries = 0;
   23
   24   for (i = 0; i < maxEntries; i++) {
   25     Map_noKey(BODY(body)->data[i].key);
   26   }
   27 }
   </src>
   
   第11-14行,判断表示当前待分配空间大小对应的Hash值,以二进制方式表示
   需要的最小位数。
   第15行求当前哈希表的空间大小
   第17-19行,分配对应哈希表空间
   第24-26行,将哈希表的每个单元的键初始化为空。以表示该单元可用。
b) 析构函数
<src>
0  template <class KeyT, class DataT>
1  LHash<KeyT,DataT>::~LHash()
2  {
3    clear(0);
4  }
</src>
    功能:该函数回收为哈希表分配的内存空间
    
    细解:第3行通过传入参数0调用clear函数,回收内存空间。
    
    clear函数
    <src>
    0  template <class KeyT, class DataT>
  1  void
  2  LHash<KeyT,DataT>::clear(unsigned size)
  3  {
  4    if (body) {
  5      unsigned maxEntries = hashSize(BODY(body)->maxBits);
  6      unsigned i;
  7
  8      for (i = 0; i < maxEntries; i++) {
  9        if (! Map_noKeyP(BODY(body)->data[i].key)) {
  10         Map_freeKey(BODY(body)->data[i].key);
  11       }
  12     }
  13     free(body);
  14     body = 0;
  15   }
  16   
  17   if (size != 0) {
  18     alloc(roundSize(size));
  19   }
  20 }
  </src>
   
   第5-15行首先获取哈希表的空间大小,然后遍历哈希表,并对不为空的单元对应
   的Key进行内存回收,最后回收整个哈希表空间。
   第17-19行判断,如果传入clear的参数不为零,则调用roundSize和alloc函数重
   新为哈希表分配空间。
c) 赋值函数
<src>
0  template <class KeyT, class DataT>
1  LHash<KeyT,DataT> &
2  LHash<KeyT,DataT>::operator= (const LHash<KeyT,DataT> &other)
3  {
4    #ifdef DEBUG
5     cerr << "warning: LHash::operator= called/n";
6    #endif
7
8    if (&other == this) {
9      return *this;
10   }
11
12   /*
13   * copy hash entries from old to new 
14   */
15   if (other.body) {
16     unsigned maxEntries = hashSize(BODY(other.body)->maxBits);
17     /*
18     * ensure we have exactly the same size as source table
19     */
20     clear(0);
21     alloc(maxEntries);
22     
23     for (unsigned i = 0; i < maxEntries; i++) {
24       KeyT thisKey = BODY(other.body)->data[i].key;
25 
26       if (!Map_noKeyP(thisKey)) {
27         /*
28         * Copy key
29         */
30         BODY(body)->data[i].key = Map_copyKey(thisKey);
31
32         /*
33         * Initialize data, required for = operator
34         */
35         new (&(BODY(body)->data[i].value)) DataT;
36   
37         /*
38         * Copy data
39         */
40         BODY(body)->data[i].value = BODY(other.body)->data[i].value;
41       }
42     }
43     BODY(body)->nEntries = BODY(other.body)->nEntries;
44   } else {
45     clear(0);
46   }
47   return *this;
48 }
</src>
    功能:将“=”左边的对象初始化右边的对象。
    
    细解:
    第8-10行,判断当前赋值运算是否发生了自我我赋值问题。
    第15行判断源对象哈希表是否为空,若为空,则运行第45行
    将当前对象哈希表置为空,否则运行第16-43行。
    第14-43行,首先将当前哈希表设置为空,然后调用将哈希表
    大小设置为源对象哈希表大小,并通过遍历源对象哈希表的
    方法进行“键->值”对拷贝。
    第47行返回当前对象的引用。
d) 拷贝构造函数
<src>
0  template <class KeyT, class DataT>
1  LHash<KeyT,DataT>::LHash(const LHash<KeyT,DataT> &source)
2   : body(0)
3  {
4    #ifdef DEBUG
5    cerr << "warning: LHash copy constructor called/n";
6    #endif
7    *this = source;
8  }
</src>
    功能:将当前对象初始化为传入的对象。
    
    细解:第7行通过调用重载的赋值运算符函数,达到将当前对象初始化为
    传入的对象。
e) 查找函数
<src>
0  template <class KeyT, class DataT>
1  DataT *
2  LHash<KeyT,DataT>::find(KeyT key, Boolean &foundP) const
3  {
4    unsigned index;
5
6    if (foundP = locate(key, index)) {
7      return &(BODY(body)->data[index].value);
8    }
9     else {
10     return 0;
11   }
12 }
</src>
    功能:在哈希表中查找key,如果key存在则将foundP设为true,同时返回
    当前key对应的value的指针;否则将foundP设为false,并返回空地址。
    
    细解:第6行通过调用locate函数,来定位当前key在哈希表中对应的index。
    如果key存在则返回true,否则返回false。
    
    locate函数
    <src>
  0  template <class KeyT, class DataT>
  1  Boolean
  2  LHash<KeyT,DataT>::locate(KeyT key, unsigned &index) const
  3  {
  4    assert(!Map_noKeyP(key));
  5
  6    if (body) {
  7      unsigned maxBits = BODY(body)->maxBits;
  8      register MapEntry<KeyT,DataT> *data = BODY(body)->data;
  9 
  10     if (maxBits < minHashBits) {
  11       /*
  12       * Do a linear search
  13       */
  14       unsigned nEntries = BODY(body)->nEntries;
  15       register unsigned i;
  16
  17       for (i = 0; i < nEntries; i++) {
  18         if (LHash_equalKey(data[i].key, key)) {
  19           index = i;
  20           return true;
  21         }
  22       }
  23       index = i;
  24       return false;
  25     } 
  26     else {
  27       /*
  28       * Do a hashed search
  29       */
  30       unsigned hash = LHash_hashKey(key, maxBits);
  31       unsigned i;
  32 
  33       for (i = hash; ; i = (i + 1) & hashMask(maxBits))
  34       {
  35         if (Map_noKeyP(data[i].key)) {
  36           index = i;
  37           return false;
  38         } 
  39         else if (LHash_equalKey(data[i].key, key)) {
  40           index = i;
  41           return true;
  42         }
  43         #ifdef DEBUG
  44          collisionCount += 1;
  45         #endif
  46       }
  47     }
  48   } 
  49   else {
  50     return false;
  51   }
  52 }
    </src>
    
    功能:查找key在data数组中对应的index。如果key在哈希表中存在,则返回true
    并返回key在hash表中对应的index;否则返回false。
    
    细解:
    第10行判断当前哈希表的长度是否小于等于8,若小于等于8则进行线性搜索,同时
    保存key对应的index,若key不存在则将index设为key将要被存储的位置。若哈希
    表的长度大于8,则进行哈希搜索。
    第33-46行,采用开发地址线性探测的方法来定位当前key在哈希表中对应的index值。
    若不存在该key,则设index为当前key将要被存储的位置,返回false;否者设置index
    为当前key在hash表中的储存位置,返回true。
    
    注:locate函数在本哈希表中是一个比较重要的私有函数,采用了开放地址线性探测
    定位的方法达到查找某一key的对应的index的目的,若key不存在于hash表中,则将
    index设为key在哈希表中将要被保存的位置。
        由于locate函数的上述特性,因此后续的插入和删除函数等都以locate函数为基础
    达到实现相应功能的目的。
f) 插入函数
<src>
0  template <class KeyT, class DataT>
1  DataT *
2  LHash<KeyT,DataT>::insert(KeyT key, Boolean &foundP)
3  {
4    unsigned index;
5
6    assert(!(Map_noKeyP(key)));
7
8    /*
9    * Make sure there is room for at least one entry
10   */
11   if (body == 0) {
12    alloc(1);
13   }
14 
15   if (foundP = locate(key, index)) {
16     return &(BODY(body)->data[index].value);
17   }
18   else {
19     unsigned maxEntries = hashSize(BODY(body)->maxBits);
20     unsigned nEntries = BODY(body)->nEntries;
21
22     /*
23     * Rehash table if necessary
24     */
25     unsigned minSize = roundSize(nEntries + 1);
26
27     if (minSize > maxEntries) {
28       LHashBody<KeyT,DataT> *oldBody = BODY(body);
29       unsigned i;
30  
31       /*
32       * Since LHash_maxEntriesLimit is a power of two minus 1
33       * we need to check this only when the array is enlarged
34       */
35       assert(nEntries < LHash_maxEntriesLimit);
36 
37       alloc(minSize);
38       BODY(body)->nEntries = nEntries;
39
40       if (BODY(body)->maxBits < minHashBits) {
41         /*
42         * Just copy old entries to new storage, no reindexing
43         * required.
44         */
45         memcpy(BODY(body)->data, oldBody->data,
46         sizeof(oldBody->data[0]) * nEntries);
47       }
48       else {
49         /*
50         * Rehash
51         */
52         for (i = 0; i < maxEntries; i++) {
53           KeyT key = oldBody->data[i].key;
54  
55           if (! Map_noKeyP(key)) {
56             (void)locate(key, index);
57             memcpy(&(BODY(body)->data[index]), &(oldBody->data[i]),
58             sizeof(oldBody->data[0]));
59           }
60         }
61       }
62       free(oldBody);
63 
64       /*
65       * Entries have been moved, so have to re-locate key
66       */
67       (void)locate(key, index);
68     }
69
70     BODY(body)->data[index].key = Map_copyKey(key);
71 
72     /*
73     * Initialize data to zero, but also call constructors, if any
74     */
75     memset(&(BODY(body)->data[index].value), 0,
76     sizeof(BODY(body)->data[index].value));
77     new (&(BODY(body)->data[index].value)) DataT;
78 
79     BODY(body)->nEntries++;
80
81     return &(BODY(body)->data[index].value);
82   }
83 }
</src>
    功能:将key插入到哈希表中,同时返回key对应的value储存地址。如果key已经
    在哈希表中存在,则将foundP设为true,否则设为false。
    
    细解:
    第11-13行判断当前哈希表是否已经分配空间,若未分配,则为当前哈希表分配一个
    单元的空间。
    第15行通过调用locate函数来判断当前key是否已经存在于哈希表中。若当前哈希表
    中已经存在该key则直接返回key对应的value的地址。否则将key需要被保存到哈希表
    中的位置存储于index中。
    第19-25行首先获取当前哈希表的大小及已经储存的单元数,然后通过调用roundSize
    函数获取增加一个元素后哈希表至少需要的空间大小(minSize)。
    第27行判断minSize是否大于maxEntries,若小于maxEntries,则直接调用第70-81行。
    否则调用第28-67行。
    第28-67行重新扩展哈希表的地址空间,并将原空间的单元值,复制到新分配的空间上。
    第37行重新分配哈希表空间大小,第38行将新分配的哈希表中保存的元素数初始化为
    原哈希表保存的元素数。
    第40行判断新哈希表的空间大小是否小于8,若小于8则进行直接拷贝。因为当哈希表
    空间大小小于8时,直接使用线性遍历搜索的方法。否则运行第48-61行。
    第48-61行对原哈希表中的元素进行rehash操作,将其插入到新分配的哈希表中。
    第62行释放旧的哈希表地址空间
    第67行定位即将被插入到哈希表中的key,在新的哈希表中对应的index值。
    第70-81行将key复制到哈希表中对应单元处,同时将其对应的value值初始化为0,并返回
    该value值的地址。
    
    注:第77行使用placement new方法达到了调用value类型对应的构造函数初始化value的目的。
g) 删除函数
<src>
0  template <class KeyT, class DataT>
1  DataT *
2  LHash<KeyT,DataT>::remove(KeyT key, Boolean &foundP)
3  {
4    unsigned index;
5
6    /*
7    * Allocate pseudo-static memory for removed objects (returned by
8    * remove()). We cannot make this static because otherwise 
9    * the destructor for DataT would be called on it at program exit.
10   */
11   if (removedData == 0) {
12     removedData = (DataT *)malloc(sizeof(DataT));
13     assert(removedData != 0);
14   }
15
16   if (foundP = locate(key, index)) {
17     Map_freeKey(BODY(body)->data[index].key);
18     Map_noKey(BODY(body)->data[index].key);
19     memcpy(removedData, &BODY(body)->data[index].value, sizeof(DataT));
20 
21     if (BODY(body)->maxBits < minHashBits) {
22       /*
23       * Linear search mode -- Just move all entries above the
24       * the one removed to fill the gap.
25       */
26       unsigned nEntries = BODY(body)->nEntries;
27       
28       memmove(&BODY(body)->data[index],
29       &BODY(body)->data[index+1],
30       (nEntries - index - 1) * sizeof(BODY(body)->data[0]));
31       Map_noKey(BODY(body)->data[nEntries - 1].key);
32     }
33     else {
34       /*
35       * The entry after the one being deleted could actually
36       * belong to a prior spot in the table, but was bounced forward due
37       * to a collision.   The invariant used in lookup is that
38       * all locations between the hash index and the actual index are
39       * filled.  Hence we examine all entries between the deleted
40       * position and the next free position as whether they need to
41       * be moved backward.
42       */
43       while (1) {
44         unsigned newIndex;
45 
46         index = (index + 1) & hashMask(BODY(body)->maxBits);
47
48         if (Map_noKeyP(BODY(body)->data[index].key)) {
49           break;
50         }
51
52         /* 
53         * If find returns false that means the deletion has
54         * introduced a hole in the table that would prevent
55         * us from finding the next entry. Luckily, find 
56         * also tells us where the hole is.  We move the 
57         * entry to its rightful place and continue filling
58         * the hole created by this move.
59         */
60         if (!locate(BODY(body)->data[index].key, newIndex)) {
61           memcpy(&(BODY(body)->data[newIndex]),
62           &(BODY(body)->data[index]),
63           sizeof(BODY(body)->data[0]));
64           Map_noKey(BODY(body)->data[index].key);
65         }
66       }
67     }
68     BODY(body)->nEntries--;
69     return removedData;
70   }
71   else {
72     return 0;
73   }
74 }
</src>
    功能:如果当前key存在于哈希表中,则将当前key从哈希表中删除,同时将foundP设为true,
    并返回key对应的value的地址。否则将foundP设为false,并返回空地址。
    
    细解:第16行调用locate函数,判断key是否在哈希表中存在,及其对应的index值。
    第17-19行释放当前key,同时将其对应的单元设为free,表示该单元可被使用。同时将当前
    key对应的data值复制到*removedData中。
    第21行判断当前哈希表的空间大小是否小于8。若小于8,则调用直接将后续单元移动过来填充
    被释放的单元,并将最后一个移出的单元的key设为空,以表示该单元可用。否则运行第43-66
    行。
    第43-66行将当前被删除的元素后的非空单元移动到新的位置,直到到达空单元为止。这样做
    是因为线性地址探测的哈希表会搜寻元素时会停止在可用的单元处。以此来完成线性探测搜寻
    地址的方法。
    第68行将记录哈希表中保存元素个数的变量减1。
LHashIter类
a) 构造函数
<src>
0  template <class KeyT, class DataT>
1  LHashIter<KeyT,DataT>::LHashIter(const LHash<KeyT,DataT> &lhash,
2                    int (*keyCompare)(KeyT, KeyT))
3           : myLHashBody(BODY(lhash.body)), current(0),
4            numEntries(lhash.numEntries()), sortFunction(keyCompare)
5  {
6    /*
7    * Note: we access the underlying LHash through the body pointer,
8    * not the top-level LHash itself.  This allows the top-level object
9    * to be moved without affecting an ongoing iteration.
10   * XXX: This only works because
11   * - it is illegal to insert while iterating
12   * - deletions don't cause reallocation of the data
13   */
14   if (sortFunction && myLHashBody) {
15     sortKeys();
16   } 
17   else {
18     sortedKeys = 0;
19   }
20 }
</src>
    功能:使用lhash和键比较函数初始化LHashIter迭代器对象。
    
    细解:
    第3-4行使用成员初始化列表的方式初始化LHashIter的成员变量。
    第14行判断键比较函数和哈希体是否为空,若均不为空则调用对
    键值进行排序的函数sortKeys。否则运行第18行,将sortedKeys
    初始化为空。
    
    sortKeys函数
    <src>
  0   template <class KeyT, class DataT>
  1  void
  2  LHashIter<KeyT,DataT>::sortKeys()
  3  {
  4    /*
  5    * Store keys away and sort them to the user's orders.
  6    */
  7    unsigned maxEntries = hashSize(myLHashBody->maxBits);
  8  
  9    unsigned *sortedIndex = new unsigned[numEntries];
  10   assert(sortedIndex != 0);
  11  
  12   unsigned i;
  13
  14   unsigned j = 0;
  15   for (i = 0; i < maxEntries; i++) {
  16     if (!Map_noKeyP(myLHashBody->data[i].key)) {
  17       sortedIndex[j++] = i;
  18     }
  19   }
  20   assert(j == numEntries);
  21 
  22   /*
  23   * Due to the limitations of the qsort interface we have to 
  24   * pass extra information to compareIndex in these global
  25   * variables - yuck. 
  26   */
  27   LHash_thisKeyCompare = (int(*)())sortFunction;
  28   LHash_thisBody = myLHashBody;
  29   qsort(sortedIndex, numEntries, sizeof(*sortedIndex), compareIndex);
  30    
  31   /*
  32   * Save the keys for enumeration.  The reason we save the keys,
  33   * not the indices, is that indices may change during enumeration
  34   * due to deletions.
  35   */
  36   sortedKeys = new KeyT[numEntries];
  37   assert(sortedKeys != 0);
  38  
  39   for (i = 0; i < numEntries; i++) {
  40     sortedKeys[i] = myLHashBody->data[sortedIndex[i]].key;
  41   }
  42 
  43   delete [] sortedIndex;
  44 }
    </src>
    功能:对哈希表中单元按key进行排序。
    
    细解:
    第9行首先定义一个unsigned类型的指针数组,用于保存key对应的index值。
    第15-19行将指针数组的内容初始化为哈希表中的key对应的index值。
    第29行通过调用qsort和compareIndex函数对sortedIndex中的index按key
    值排序。
    第36-43行,将排好序的index对应的key保存到sortedKeys成员数组变量中。
    同时释放临时变量sortedIndex占用的内存。
    
b) 析构函数
<src>
0  template <class KeyT, class DataT>
1  LHashIter<KeyT,DataT>::~LHashIter()
2  {
3    delete [] sortedKeys;
4  }
</src>
    功能:回收为sortedKeys分配的内存。
    
    注:当指针变量被初始化为0时,可以直接调用对其进行delete操作,而不会引起
    错误。
c) init函数
<src>
0  template <class KeyT, class DataT>
1  void 
2  LHashIter<KeyT,DataT>::init()
3  {
4    delete [] sortedKeys;
5    
6    current = 0;
7
8    {
9      /*
10     * XXX: fake LHash object to access numEntries()
11     */
12     LHash<KeyT,DataT> myLHash(0);
13 
14     myLHash.body = myLHashBody;
15     numEntries = myLHash.numEntries();
16     myLHash.body = 0;
17   }
18
19   if (sortFunction && myLHashBody) {
20     sortKeys();
21   }
22   else {
23     sortedKeys = 0;
24   }
25 }
</src>
    功能:用于对当前对象进行初始化,并根据情况决定是否对哈希表进行
    排序操作。
    
    细解:第19-21行判断,sortFunction和myLHashbody是否非空,如果均
    不为空,则调用sortKeys进行排序操作。
d) next函数
<src>
0  template <class KeyT, class DataT>
1  DataT *
2  LHashIter<KeyT,DataT>::next(KeyT &key)
3  {
4
5    if (myLHashBody == 0) {
6      return 0;
7    }
8     else {
9      unsigned index;
10
11     if (sortedKeys) {
12       /*
13       * Sorted enumeration -- advance to next key in sorted list
14       */
15       if (current == numEntries) {
16         return 0;
17       }
18
19       /*
20       * XXX: fake LHash object to access locate()
21       */
22       LHash<KeyT,DataT> myLHash(0);
23
24       myLHash.body = myLHashBody;
25       myLHash.locate(sortedKeys[current++], index);
26       myLHash.body = 0;;
27    }
28    else {
29      /*
30      * Detect deletions by comparing old and current number of 
31      * entries.
32      * A legal deletion can only affect the current entry, so
33      * adjust the current position to reflect the next entry was
34      * moved.
35      */
36      if (myLHashBody->nEntries != numEntries) {
37        assert(myLHashBody->nEntries == numEntries - 1);
38  
39        numEntries --;
40        current --;
41      }
42  
43      /*
44      * Random enumeration mode
45      */
46      unsigned maxBits = myLHashBody->maxBits;
47  
48      if (maxBits < minHashBits) {
49        /*
50        * Linear search mode - advance one to the next entry
51        */
52        if (current == numEntries) {
53          return 0;
54        }
55       } 
56      else {
57         unsigned maxEntries = hashSize(maxBits);
58
59         while (current < maxEntries &&
60            Map_noKeyP(myLHashBody->data[current].key))
61         {
62           current++;
63         }
64 
65         if (current == maxEntries) {
66           return 0;
67         }
68      }
69
70      index = current ++;
71    }
72
73    key = myLHashBody->data[index].key;
74    return &(myLHashBody->data[index].value);
75  }
76 }
</src>
    功能:用于获取当前哈希表中单元对应key和value,同时将其初始化为下一个单元。
    
    细解:
    第11行判断是否使用了排序遍历的方法,如果使用了该方法则运行第12-27行,否则运行
    第29-71行。
    第12-27行,遍历sortedKeys中key,并获得其在哈希表中对应的index
    第29-71行,使用线性遍历的方法,获取下一个key在hash表中对应的index
    第73行将当前key保存到函数的输入参数中
    第74行返回当前key对应value值的地址
--------------------------------------
知识点:
--------------------------------------
1、哈希表
   (1) 冲突消解方法
       哈希表一般可采用两种冲突消解方法:链地址法、线性地址探测方法
       i、链地址法
          链地址消解方法即将属于哈希到同一个单元的值,通过链的方法消解;
      ii、线性探测法
          线性探测的方法即将哈希到同一个单元的值,依次向下搜索,直到
          找到一个空的单元并将该值存入。若已经搜索到哈希表最后一个单元
          则回到第一个单元处继续搜索,直到找到空单元位置。所以采用线性
          探测的哈希表大小一般要大于存储的元素个数。一般存储元素的个数
          为哈希表空间大小的0.85(装载系数)左右;
          
   (2) 开放地址线性探测的哈希表
    采用开放地址线性探测的哈希表,有两个操作值得关注
    i、插入操作
       在开放地址线性探测的哈希表中进行新元素插入时,当装载的元素数
       超过装载系数时,需要进行哈希表的空间扩充。这是需要对将原哈希
       表中保存的所有元素进行重新哈希,并将每个元素保存到新的哈希表
       中;
   ii、删除操作
       在线性探测的哈希表中进行元素删除操作时,需要将保存该元素的单元
       置为可用单元,然后将该单元至下一个可用单元之间的所有元素重新哈
       希,并将原本哈希到该置空单元位置处或之前位置处的元素重新储存,
       同时在存储后,将旧单元置空。
2、迭代器模式
       对某一个对象中的元素进行迭代时,一般采用迭代器模式。即为其定义一个
   迭代器,同时将该对象传入迭代器中,然后通过迭代器提供的方法,迭代遍历
   该对象中的每个元素。
3、placement new
       placement new可以在不对对象重新进行内存分配的同时,达到调用构造函数
   初始化对象的目的。
   e.g.
       new (&(BODY(body)->data[index].value)) DataT;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值