zoukankan      html  css  js  c++  java
  • 散列表

      散列表Hash table,也叫哈希表),是根据关键字(Key value)而直接访问在内存存储位置的数据结构。也就是说,把键值通过一个函数的计算,映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。类似于数学中的映射关系。

      现假设关键字的全域为U = {k | 0 <= k < n}

    1、直接寻址表

      如果全域U比较小,即n的数值比较小,且没有重复元素,那么可以用数组T[0, m-1](m = n)做为直接寻址表,每个槽位T[k] = tk,tk = NIL表示不存在关键字为k的元素,否则表示有关键字为k的元素。

    SEARCH(T, x)
        return T[x]
    
    INSERT(T, x)
        T[x] = x
    
    DELETE(T, x)
        T[x] = NIL

    直接寻址法限制较多,不常用。

     2、散列表

    当全域U很大时,可以用函数h把U中元素k映射到表T[1, m]中的某个位置,即:

    h: U{k} --> T[i], (k IN [0, n-1], i IN [0, m-1])

    这样我们处理的值就从n降到了m。这里的函数h称为散列函数。

    好的散列函数应该满足如下性质:每个关键字都等可能的映射到T[0, m-1]中的m个槽位中,且与其他关键字散列到哪个槽位无关

    但这个性质很难满足. 散列函数假定关键字为自然数N的子集,如果关键字不是自然数,则将其变换为自然数。

    一般有如下几种散列函数:

    2.1、除法散列

    h(k) = k mod m  // m表示槽位数,k表示关键字

    一般讲m选择为与2的整数幂不太接近的质数。

    2.2、乘法散列

    h(k) = floor(m(kA mod 1)) // 0 < A < 1

    其中 kA mod 1 表示取 kA的小数部分,floor表示向下取整。

    A可以取黄金分割数 (sqrt(5) - 1) / 2

    2.3 解决冲突

    从全域U --> 表T, 可能存在k1和k2同时映射到T[i]的情况,发生了冲突,可以通过链接法来解决。

    链接法实际是使用数组T[0, m-1], 数组的任意元素T[i]为一个链表的表头来实现的。

    3、散列表简单实现

    采用除法散列,并用双链表解决散列冲突的简单散列表如下:

      1 static const int hash_size = 331;
      2 #define hash(x) ((unsigned int)x % hash_size)
      3 
      4 struct listNode
      5 {
      6     int key;
      7     int value;
      8     struct listNode *next;
      9     struct listNode *prev;
     10     listNode(int x, int y): key(x), value(y), next(NULL), prev(NULL) {}
     11     listNode(): key(0), value(0), next(NULL), prev(NULL) {}
     12 };
     13 
     14 class hash_table
     15 {
     16 public:
     17     hash_table()
     18     {
     19         for (int i = 0; i < hash_size; i++)
     20         {
     21             hash_map[i].next = &hash_map[i]; 
     22             hash_map[i].prev = &hash_map[i]; 
     23         }
     24         elem_size = 0;
     25     }
     26     struct listNode *find(int key);
     27     void insert(int key, int value);
     28     void erase(int key);
     29     bool empty();
     30     int size();
     31 private:
     32     struct listNode hash_map[hash_size];
     33     int elem_size;
     34 };
     35 
     36 void __list_add(struct listNode *prev, struct listNode *next, struct listNode *node)
     37 {
     38     prev->next = node;
     39     node->next = next;
     40     next->prev = node;
     41     node->prev = prev;
     42 }
     43 
     44 void list_add(struct listNode *head, struct listNode *node)
     45 {
     46     __list_add(head, head->next, node);
     47 }
     48 
     49 void __list_del(struct listNode *prev, struct listNode *next)
     50 {
     51     prev->next = next;
     52     next->prev = prev;
     53 }
     54 
     55 void list_del(struct listNode *node)
     56 {
     57     __list_del(node->prev, node->next);
     58 }
     59 
     60 bool list_empty(struct listNode *node)
     61 {
     62     return (node->next == node);
     63 }
     64 
     65 bool list_tail(struct listNode *head, struct listNode *node)
     66 {
     67     return (node->next == head);
     68 }
     69 
     70 bool hash_table::empty()
     71 {
     72     return (elem_size == 0);
     73 }
     74 
     75 int hash_table::size()
     76 {
     77     return elem_size;
     78 }
     79 
     80 struct listNode *hash_table::find(int key)
     81 {
     82     struct listNode *head = &hash_map[hash(key)], *visit = head;
     83     while (!list_tail(head, visit))
     84     {
     85         visit = visit->next;
     86         if (visit->key == key)
     87             return visit;
     88     }
     89     return NULL;
     90 }
     91 
     92 void hash_table::insert(int key, int value)
     93 {
     94     struct listNode *visit = NULL;
     95     
     96     visit = find(key);
     97     if (visit != NULL)
     98     {
     99         visit->value = value;
    100     }
    101     else
    102     {
    103         visit = new listNode(key, value);
    104         list_add(&hash_map[hash(key)], visit);
    105         elem_size++;
    106     }
    107 }
    108 
    109 void hash_table::erase(int key)
    110 {
    111     struct listNode *visit;
    112 
    113     visit = find(key);
    114     if (visit != NULL)
    115     {
    116         list_del(visit);
    117         delete visit;
    118         elem_size--;
    119     }
    120 }

    为了简单起见,没有实现rehash方法, 仅仅作为一个散列表的简单实现.

  • 相关阅读:
    线性回归的从零开始实现
    比赛总结
    计数学习笔记
    DP计数问题
    多项式学习笔记
    数据结构学习笔记
    子集运算学习笔记
    待学习
    ICPC2018焦作 题解
    ICPC2018焦作 H题 Can You Solve the Harder Problem?
  • 原文地址:https://www.cnblogs.com/ym65536/p/4132883.html
Copyright © 2011-2022 走看看