一个哈希表的实现

来源:互联网 发布:替换电脑软件图标 编辑:程序博客网 时间:2024/04/27 13:48

一个哈希表的实现

转:http://blog.csdn.net/shuqin1984/article/details/6587503

 哈希表是数组、链表及数学算法的一个综合应用, 无论在理论上还是实践上都是非常有价值的。 废话不多说了, 贴上自己的实现吧,以供参考,有错误之处,恳请指出。 还需要做的一个工作是, 为实现中用到的链表和哈希表设计详尽苛刻的测试。

        该哈希表包括四个文件: common.h , LinkList.c, Hashtable.c , main.c . 将它们放在同一个文件夹中,按照下面的方式编译运行

        $ gcc -Wall *.c -o main

        $ main

        或者 一个简单的 makefile 文件: 

        OBJS = Hashtable.o main.o LinkList.o
         mhash: $(OBJS)
         [tab]cc -o mhash $(OBJS)
         HashSearch.o: Hashtable.c common.h
         [tab]cc -c Hashtable.c
         main.o: main.c common.h
         [tab]cc -c main.c
         LinkList.o: LinkList.c common.h
         [tab]cc -c LinkList.c  
         .PHONY: clean
         clean:
         [tab]-rm $(OBJS) mhash
        

         $ make

         $ mhash

         下面是各个文件的具体实现: 

         common.h

   

[cpp] view plaincopyprint?
  1. /* 
  2.  * common.h 
  3.  * 关于哈希查找和链表结构的声明和定义。 
  4.  * 
  5.  * 哈希查找法:  
  6.  * 采用字符串散列函数的哈希函数和链地址法的冲突解决方案 
  7.  * 
  8.  */  
  9.   
  10. enum { OK = 1, ERROR = 0, TRUE = 1, FALSE = 0, FAILURE = 1, LEN_OF_TABLE = 13, RECORD_NUM = 95 };   
  11.   
  12. typedef struct {          /* 记录类型 */  
  13.          char  *key;  
  14.      int   value;   
  15. } Record;  
  16.   
  17. typedef struct node *LLNptr;  
  18.   
  19. typedef struct node {     /*  链表结点类型 */  
  20.      Record  data;  
  21.      LLNptr  next;    
  22. } LLNode;  
  23.   
  24. typedef int  Status;  
  25.   
  26. /* 单链表的函数声明,主要依照严蔚敏老师《数据结构C语言版》中的描述 */  
  27.    
  28. Status  InitList(LLNptr *list);              /* 创建带头结点的单链表 */      
  29. int     IsEmpty(LLNptr list);                /* 判断单链表是否为空   */  
  30. int     ListLength(LLNptr list);             /* 返回链表长度,即记录的数目(不含头结点) */  
  31. Status  GetRecord(LLNptr list, int i, Record *e);      /* 返回链表中第 i 个位置上的结点,并保存在 e 中 */  
  32. Status  ListInsert(LLNptr list, int i, Record e);      /* 将记录 e 插入到链表 list 中的第 i 个位置上 */  
  33. Status  ListDelete(LLNptr list, int i, Record *e);     /* 将链表 list 中的第 i 个位置上的记录删除,并用 e 返回 */  
  34. Status  ListTraverse(LLNptr list, void (*visit)(Record *e));  /* 使用 visit 遍历链表 */  
  35. Status  ListPrint(LLNptr list);                        /* 打印链表内容 */        
  36. void  printRecord(Record *e);                          /* 打印记录内容 */  
  37. int   Equal(Record *e1, Record *e2);                   /* 判断记录的相等性 */  
  38.   
  39. /* 返回链表 list 中与 e 满足 compare 关系的记录的指针; 如果不存在,返回 NULL */  
  40. Record*  PLocateRecord(LLNptr list, Record e, int (*compare)(Record *e1, Record *e2));  
  41.   
  42. /* 哈希查找的函数声明  */  
  43.   
  44. int hash(char* key);     /* 计算关键字的哈希值 */  
  45. Status InitTable(LLNptr hashtable[]);    /* 初始化哈希表 hashtable */  
  46. Status HashInsert(LLNptr hashtable[], Record e);   /* 将记录插入哈希表 hashtable 中 */  
  47. Record* HashSearch(LLNptr hashtable[], Record e);      /* 根据记录关键字查找:若有则返回指向该记录的指针,否则返回 NULL */  
  48. Status HashTraverse(LLNptr hashtable[]);           /* 遍历哈希表 */  

      LinkList.c

      

[cpp] view plaincopyprint?
  1. /*  LinkList.c  */  
  2. /*  带头结点的单链表实现,头结点存储表长信息  */  
  3.   
  4. #include <stdio.h>  
  5. #include <stdlib.h>  
  6. #include <string.h>  
  7. #include "common.h"  
  8.   
  9. Status  InitList(LLNptr* list)  
  10. {   
  11.      LLNptr head = (LLNptr)malloc(sizeof(LLNode));  
  12.      if (!head) {  
  13.               fprintf(stderr, "Error: fail to allocate memory!\n");   
  14.               return ERROR;  
  15.          }           
  16.      head->data.value = 0;      /* 头结点的 value 域存储表长 */    
  17.          head->data.key = NULL;     /* 头结点的 key 域 未用     */    
  18.      head->next = NULL;  
  19.          *list = head;  
  20.      return  OK;      
  21. }    
  22.   
  23. int  IsEmpty(LLNptr list)  
  24. {  
  25.     return list->data.value == 0;  
  26. }  
  27.   
  28. int  ListLength(LLNptr list)  
  29. {  
  30.     return list->data.value;  
  31. }  
  32.   
  33. Status GetRecord(LLNptr list, int i, Record *e)  
  34. {  
  35.       /* 取得表list中的第i个元素, 并用e返回 */  
  36.         
  37.       LLNptr p = list->next;   /* p 指向第一个记录结点 */  
  38.         
  39.           if (IsEmpty(list)) {  
  40.          fprintf(stderr, "Error: list empty!\n");  
  41.          return  ERROR;  
  42.       }  
  43.       if (i < 1 || i > ListLength(list)) {  
  44.          fprintf(stderr, "Error: position parameter %d out of range!\n", i);  
  45.          return  ERROR;  
  46.       }  
  47.       while(--i) p = p->next;  /* p 指向第i个元素 */  
  48.       *e = p->data;  
  49.       return OK;     
  50. }  
  51.   
  52. Record* PLocateRecord(LLNptr list, Record e, int (*compare)(Record *e1, Record *e2))  
  53. {  
  54.         
  55.       /* 返回表list中与给定元素e满足compare关系的记录指针 */  
  56.         
  57.       LLNptr p = list->next;  
  58.          
  59.       while (p) {  
  60.          if (compare(&p->data, &e))  
  61.           return &p->data;  
  62.          p = p->next;  
  63.       }  
  64.       return NULL;      
  65. }     
  66.   
  67. Status  ListInsert(LLNptr list, int i, Record e)  
  68. {  
  69.       /* 将记录 e 插入表list中的第 i 个位置上 */  
  70.       
  71.       LLNptr s, p = list;  
  72.       int j = 0;    /* j 作计数器 */  
  73.         
  74.           if (i < 1 || i > ListLength(list)+1) {  
  75.          fprintf(stderr, "Error: position parameter %d out of range!\n", i);  
  76.          return  ERROR;  
  77.       }  
  78.       while (p && j < i-1) { p = p->next; j++; }  
  79.       s = (LLNptr)malloc(sizeof(LLNode));  
  80.       if (!s) {  
  81.           fprintf(stderr, "Error: fail to allocate memory!\n");  
  82.           return ERROR;  
  83.       }  
  84.       s->data = e; s->next = p->next;  
  85.       p->next = s;  
  86.       list->data.value++;  
  87.       return OK;  
  88. }  
  89.   
  90. Status  ListDelete(LLNptr list, int i, Record *e)  
  91. {  
  92.       /* 删除表list中的第i个位置上的记录,并用 e 返回 */  
  93.         
  94.       LLNptr p1 = list;  
  95.       LLNptr p2;  
  96.       int j = 0;  /* j 作计数器 */  
  97.         
  98.       if (IsEmpty(list)) {  
  99.          printf("Error: list empty!\n");  
  100.          return  ERROR;  
  101.       }  
  102.       if (i < 1 || i > ListLength(list)) {  
  103.          printf("Error: invalid index!\n");  
  104.          return  ERROR;  
  105.       }  
  106.       while (p1->next && j < i-1) { /* p1 指向第 i-1 个元素 */  
  107.           p1 = p1->next;  
  108.           j++;  
  109.       }  
  110.       p2 = p1->next;         /* p2 指向第 i 个元素 */  
  111.           *e = p2->data;  
  112.           p1->next = p2->next;  
  113.           free(p2);  
  114.           list->data.value--;  
  115.       return OK;  
  116.         
  117. }  
  118.   
  119. Status  ListTraverse(LLNptr list, void (*visit)(Record *e))  
  120. {  
  121.     /* 用visit函数遍历表list中的元素有且仅有一次 */  
  122.       
  123.      LLNptr p = list->next;  
  124.        
  125.      if (IsEmpty(list)) {  
  126.          printf("list empty!\n");  
  127.          return  ERROR;  
  128.       }  
  129.      while (p) {  
  130.          visit(&p->data);  
  131.          p = p->next;  
  132.      }  
  133.      return OK;  
  134. }  
  135.   
  136. Status ListPrint(LLNptr list)  
  137. {  
  138.     return ListTraverse(list, printRecord);  
  139. }  
  140.   
  141. void  printRecord(Record *e)  
  142. {  
  143.      printf("(%s, %d)\n", e->key, e->value);  
  144. }  
  145.   
  146. int   Equal(Record *e1, Record *e2)  
  147. {  
  148.      return strcmp(e1->key,e2->key)==0;  
  149. }  

     Hashtable.c

     

[cpp] view plaincopyprint?
  1. // Hashtable.c  
  2. // 哈希函数的实现  
  3.   
  4. #include <stdio.h>  
  5. #include "common.h"   
  6.   
  7. int hash(char* key)  
  8. {  
  9.      char *p = key;  
  10.          int hash = 17;  
  11.          while (*p) {  
  12.             hash = hash * 37 + (*p);  
  13.             p++;  
  14.          }  
  15.          printf("key = %s\thash = %d , hash %% %d = %d\n" , key, hash, LEN_OF_TABLE, hash % LEN_OF_TABLE);  
  16.      return hash % LEN_OF_TABLE;  
  17. }  
  18.   
  19. Status InitTable(LLNptr table[])  
  20. {  
  21.      int i;  
  22.      for (i = 0; i < LEN_OF_TABLE; i++) {  
  23.         if (!InitList(&table[i])) {  
  24.                 return ERROR;  
  25.             }  
  26.      }  
  27.      return OK;  
  28. }  
  29.   
  30. Status HashInsert(LLNptr table[], Record e)  
  31. {        
  32.      int t_index = hash(e.key);  
  33.          if (PLocateRecord(table[t_index], e, Equal)) {  /* 哈希表中已存在该记录 */  
  34.              printf("Record exists, nothing to do.");  
  35.              return OK;  
  36.          }  
  37.      int ins_pos = ListLength(table[t_index]) + 1;  
  38.      if (!ListInsert(table[t_index], ins_pos, e)) {  
  39.              return ERROR;  
  40.          }   
  41.      return OK;  
  42. }  
  43.   
  44. Record* HashSearch(LLNptr table[], Record e)  
  45. {    
  46.      int t_index = hash(e.key);  
  47.      return PLocateRecord(table[t_index], e, Equal);  
  48. }  
  49.   
  50. Status HashTraverse(LLNptr table[])  
  51. {  
  52.     int i;  
  53.         printf("The hash table:\n");  
  54.     for (i = 0; i < LEN_OF_TABLE; i++) {  
  55.            printf("List[%d]:\n", i);   
  56.        ListPrint(table[i]);  
  57.        printf("\n");  
  58.     }  
  59.     return OK;   
  60. }  

       main.c

       

[cpp] view plaincopyprint?
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include "common.h"  
  5.   
  6. char* toString(int i);  
  7.   
  8. int main()  
  9. {  
  10.          printf("Program start up ...\n");  
  11.           
  12.      /* 表长为LEN_OF_TABLE的哈希表,每个元素为一个单链表指针 */  
  13.          LLNptr hashtable[LEN_OF_TABLE];  
  14.            
  15.          Record rds[RECORD_NUM];  
  16.          Record* pe;  
  17.          Record* qe;  
  18.      int i;  
  19.   
  20.      if (!InitTable(hashtable)) {  
  21.         fprintf(stderr, "Error: fail to initialize the hashtable!\n");  
  22.         exit(FAILURE);  
  23.      }  
  24.   
  25.          printf("initialize the hashtable successfully!\n");  
  26.          HashTraverse(hashtable);  
  27.     
  28.          for (i = 0; i < RECORD_NUM; i++) {  
  29.               rds[i].key = toString(i);  
  30.               rds[i].value = i;  
  31.               printf("Record: (%s %d) \n", rds[i].key, rds[i].value);  
  32.               printf("prepare to insert ...");  
  33.               if (!HashInsert(hashtable, rds[i])) {  
  34.                  printf("failed to insert record!");  
  35.               }      
  36.          }  
  37.      HashTraverse(hashtable);  
  38.   
  39.          pe = (Record* ) malloc(sizeof(Record));  
  40.          pe->key = "11111";  
  41.          qe = HashSearch(hashtable, *pe);  
  42.          if (qe != NULL) {  
  43.             printRecord(qe);  
  44.          }  
  45.          else {  
  46.             printf("Record Not Found.\n");  
  47.          }  
  48.            
  49.          pe->key = "11112";  
  50.          qe = HashSearch(hashtable, *pe);  
  51.          if (qe != NULL) {  
  52.             printRecord(qe);  
  53.          }  
  54.          else {  
  55.             printf("Record Not Found.\n");  
  56.          }   
  57.   
  58.      return 0;  
  59. }  
  60.   
  61. char* toString(int i)  
  62. {  
  63.    char *p = (char *)malloc(5*sizeof(char) + 1);  
  64.    char *q;  
  65.    if (!p) {  
  66.       fprintf(stderr, "Error, fail to allocate memory.");  
  67.       exit(FAILURE);  
  68.    }  
  69.    q = p;  
  70.    while (q < p+5) {  
  71.        *q = i + ' ';  
  72.        q++;     
  73.    }  
  74.    *q = '\0';  
  75.    return p;  
  76. }  

原创粉丝点击