《算法导论》第11章 散列表 (3)开放寻址


前一节介绍是最简单的冲突解决方法-链接法。开放寻址与链接法不同,所有元素都放在散列表内。
在这种方法中,散列表可能会被填满。开放寻址不需要指针,只需要计算出要存取的各个槽。
由于不用存储指针而节省的空间可以提供更多的槽。

有三种技术常用来计算开放寻址法中的探查序列:线性探查、二次探查和双重探查。
下面的实现中,三种方法的差别只在计算探查序列的那一行代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE 20

typedef struct _Entry {    
     char *key;
     char *val;
} Entry;

// 指针数组
Entry *hashmap[SIZE];

// Same as hashcode when String put to HashMap
unsigned hashcode(char *key)
{
     // Ensure >> is logical shift
     unsigned h = 0;

     // String.hashcode()
     do h = 31 * h + *key++;
     while (*key != '\0');    

     // HashMap.hash()
     h ^= (h >> 20) ^ (h >> 12);
     return h ^ (h >> 7) ^ (h >> 4);
}

Entry * hashmap_search(char *key)
{
     unsigned h = hashcode(key) % SIZE;
     unsigned h2 = h;
     Entry *entry = hashmap[h];
     while (entry != NULL) {
          if (strcmp(entry->key, key) == 0) {
               return entry;
          }

          // 线性探查。不同探查方法差别只在这一行。
          h = (h + 1) % SIZE;
          entry = hashmap[h];

          if (h == h2)
               break;
     }
     return NULL;
}

char * hashmap_insert(char *key, char *val)
{
     unsigned h = hashcode(key) % SIZE;
     printf("Insert %s - %s to bucket %d\n", key, val, h);
    
     // Find duplicate key, replace it then return old value
     unsigned h2 = h;
     Entry *entry = hashmap[h];
     while (entry != NULL) {
          if (strcmp(entry->key, key) == 0) {
               char *oldVal = entry->val;
               entry->val = val;
               return oldVal;
          }

          // Linear search
          h = (h + 1) % SIZE;
          entry = hashmap[h];

          // Check if loop to initial bucket
          if (h == h2)
               break;
     }

     // Not found, create new node to save key&val pair
     if (entry == NULL) {
          entry = malloc(sizeof(Entry));
          entry->key = key;
          entry->val = val;
          hashmap[h] = entry;
     }    

     return val;
}

void hashmap_print()
{    
     Entry *entry;
     int i;
     for (i = 0; i < SIZE; i++) {
          entry = hashmap[i];
          if (entry == NULL)
               printf("%d: null\n", i);
          else
               printf("%d: %s - %s\n", i, entry->key, entry->val);
     }
     printf("\n");    
}

int main(void)
{
     // Compare to String.hashcode() in JDK
     printf("%d\n", hashcode("helloworld"));

     hashmap_insert("aabb", "value1");
     hashmap_insert("ccdd", "value2");
     hashmap_insert("i'mcdai", "value3");

     int i;
     for (i = 0; i < 2 * SIZE + 5; i++) {
          char *key = calloc(sizeof(char), 10);
          char *val = calloc(sizeof(char), 10);
          sprintf(key, "%s%d", "aabbcc", i);
          sprintf(val, "%s%d", "val ", i);
          hashmap_insert(key, val);
     }

     // Insert duplicate key
     printf("%s\n", hashmap_insert("i'mcdai", "dupdup"));

     hashmap_print();

     printf("%s\n", hashmap_search("i'mcdai")->val);
    
     hashmap_print();

     return 1;
}





posted on 2012-03-12 21:34  毛小娃  阅读(153)  评论(0编辑  收藏  举报

导航