zoukankan      html  css  js  c++  java
  • 《算法导论》第11章 散列表 (2)散列表


    用散列表来解决直接寻址表的那两个问题。但由此带来的散列值的碰撞问题。
    最简单的解决方法是链接法,以及下一节介绍的开放寻址法。

    链接法,即把散列到同一槽中的所有元素都放在一个链表中。
    链表是无序的,在查找一个元素时需要遍历链表。
    对于删除函数,假如参数是要删除的结点,那么如果链表是双向的,删除操作可以O(1)内完成。
    在下面的删除函数中,参数是关键字,这样更为方便。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define SIZE 20
    
    // 链表结点的定义
    typedef struct _ListNode {     
         struct _ListNode *prev, *next;
         char *key;
         char *val;
    } ListNode;
    
    // 定义全局的各个槽链表的指针数组
    ListNode *hashmap[SIZE];
    
    // 这里的散列函数与Java中String及HashMap中的散列相同
    // 注意为了保证向右逻辑运算(用0而不是符号位补高位)
    // 要将h声明为无符号的
    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);
    }
    
    ListNode * hashmap_search(char *key)
    {
         unsigned h = hashcode(key) % SIZE;
         ListNode *node = hashmap[h];
         while (node != NULL) {
              // 当相同时,strcmp返回0
              if (strcmp(node->key, key) == 0) {
                   return node;
              }
              node = node->next;
         }
         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
         ListNode *node = hashmap_search(key);
         if (node != NULL) {
              char *oldVal = node->val;
              node->val = val;
              return oldVal;
         }
         
         // Not found, create new node to save key&val pair
         ListNode *newNode = malloc(sizeof(ListNode));
         newNode->prev = NULL;
         newNode->key = key;
         newNode->val = val;
         if (hashmap[h] == NULL) {
              hashmap[h] = newNode;
         } else {
              hashmap[h]->prev = newNode;
              newNode->next = hashmap[h];
              hashmap[h] = newNode;
         }
         return val;
    }
    
    char * hashmap_delete(char *key)
    {
         ListNode *node = hashmap_search(key);
         if (node != NULL) {
              // Set prev node's next to node's next
              if (node->prev == NULL) {
                   unsigned h = hashcode(key) % SIZE;
                   hashmap[h] = node->next;
              } else {
                   node->prev->next = node->next;
              }
    
              // Set next node's prev to node's prev
              if (node->next != NULL)
                   node->next->prev = node->prev;
    
              return node->val;
         }
         return NULL;
    }
    
    void hashmap_print()
    {
         int i;
         for (i = 0; i < SIZE; i++) {
              ListNode *node = hashmap[i];          
              while (node != NULL) {
                   printf("%s - %s, ", node->key, node->val);
                   node = node->next;
              }
              if (hashmap[i] != NULL)
                   printf("%d bucket\n", i);
         }
         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);
         printf("%s\n", hashmap_search("aabbcc18")->val);
         //printf("%s\n", hashmap_search("NOTFOUND")->val);
         
         // All in bucket 18: aabbcc10 => aabbcc0 => i'mcdai
         printf("%s\n", hashmap_delete("aabbcc10"));
         printf("%s\n", hashmap_delete("i'mcdai"));
         
         hashmap_print();
    
         return 1;
    }
    

  • 相关阅读:
    第六周总结
    石家庄地铁线路查询系统
    第五周总结报告
    二维数组
    第四周总结
    个人作业一(补充)
    第三周总结
    个人作业一
    开课博客
    CentOS7 网卡配置文件解释
  • 原文地址:https://www.cnblogs.com/xiaomaohai/p/6157855.html
Copyright © 2011-2022 走看看