分离链接法实现散列表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分离链接法实现散列表相关的知识,希望对你有一定的参考价值。

  散列表是一种用于查找的数据结构。其基本思想来自于索引,也可以看成是数组的一种扩展。对于一些数据信息,比如说图片文件名,如果我们要查找某张图片,通常将图片名作为关键字进行搜索。这个时候是不可能把图片名直接当成数组下标的,因此可以将图片名关键字通过某个函数映射为某个地址,或地址偏移量。那么每次要查找图片的时候直接输入关键字就能直接计算得出存储地址。其定义

                              T=h(k)

  其中k为关键字,h为映射函数,T为得到的散列表,得到的函数值为地址或地址偏移量。

  如果不同关键字通过某函数得到的散列值(地址偏移量)相同,这时就产生了冲突。解决冲突的方法一般有链接法和开放寻址法。

  冲突发生后,链接法使冲突元素共享同一个散列值,并且用链表将这些冲突关键字串起来,一旦要查找时,先计算出散列值,然后在对应的链表中进行查找。开放寻址法解决理念则完全不一样。一旦冲突发生,开放寻址法则寻找散列表中没有被填充的槽,直到找到为止。根据散列函数的不同,又有线性散列,二次散列,双重散列等等。

  下面是分离链接法的具体实现。参考自《数据结构与算法分析-C语言实现》。

  头文件:  

 1 /*
 2  * hash.h 4  * Created on: Dec 8, 2016
 5  * Author: csf
 6  */
 7 typedef int ElementType;
 8 #ifndef HASH_H_
 9 #define HASH_H_
10 #define MINTABLESIZE 5
11 #define MAXTABLESIZE 100
12 struct ListNode;
13 typedef struct ListNode *Position;
14 struct HashTbl;
15 typedef struct HashTbl *HashTable;
16 
17 int IsPrime(int x);
18 int NextPrime(int y);
19 int Hash(ElementType key,int TableSize);
20 HashTable InitializeTable(int TableSize);
21 void DestroyTable(HashTable H);
22 Position Find(ElementType key,HashTable H);
23 void Insert(ElementType key,HashTable H);
24 ElementType Retrieve(Position P);
25 int Delete(ElementType key,HashTable H);
26 #endif /* HASH_H_ */
27 
28 struct ListNode{
29     ElementType Element;
30     Position Next;
31 };
32 typedef Position List;
33 struct HashTbl{
34     int TableSize;
35     List *TheLists;
36 };

  源文件:

  1 /*
  2  * hash.c  4  * Created on: Dec 8, 2016
  5  * Author: csf
  6  */
  7 #include "hash.h"
  8 #include "stdio.h"
  9 #include "stdlib.h"
 10 int IsPrime(int x) //判断是否为素数
 11 {
 12     int i;
 13     for(i=2;i*i<x;i++){
 14         if(x%i==0)
 15             return 0;
 16     }
 17     return 1;
 18 }
 19 
 20 int NextPrime(int y) //寻找最邻近素数
 21 {
 22     while(1){
 23     if(IsPrime(y))
 24         return y;
 25     else
 26         y++;
 27     }
 28 }
 29 
 30 int Hash(ElementType key,int TableSize) //简单散列函数
 31 {
 32     return key%TableSize;
 33 }
 34 
 35 HashTable InitializeTable(int TableSize) //初始化散列表
 36 {
 37     HashTable H;
 38     int i;
 39 
 40     if(TableSize < MINTABLESIZE)
 41         return NULL;
 42     H=(struct HashTbl*)malloc(sizeof(struct HashTbl));
 43     if(H==NULL)
 44         return NULL;
 45     H->TableSize=NextPrime(TableSize);
 46     H->TheLists=malloc(sizeof(List)*H->TableSize);
 47     if(H->TheLists==NULL)
 48         return NULL;
 49     for(i=0;i<H->TableSize;i++)
 50     {
 51         H->TheLists[i]=(struct ListNode*)malloc(sizeof(struct ListNode));
 52         if(H->TheLists[i]==NULL)
 53             return NULL;
 54         else
 55             H->TheLists[i]->Next=NULL;
 56     }
 57     return H;
 58 }
 59 
 60 Position Find(ElementType key,HashTable H) //通过关键字查找元素,返回位置
 61 {
 62     Position P;
 63     List L;
 64     L=H->TheLists[Hash(key,H->TableSize)];
 65     P=L->Next;
 66     while(P!=NULL && P->Element!=key)
 67         P=P->Next;
 68     return P;
 69 }
 70 
 71 void Insert(ElementType key,HashTable H) //插入关键字
 72 {
 73     Position Pos,NewElement;
 74     List L;
 75     Pos=Find(key,H);
 76     if(Pos==NULL)
 77     {
 78         NewElement=(struct ListNode*)malloc(sizeof(struct ListNode));
 79         if(NewElement==NULL)
 80             exit(0);
 81         else
 82         {
 83             L=H->TheLists[Hash(key,H->TableSize)];
 84             NewElement->Next=L->Next;
 85             NewElement->Element=key;
 86             L->Next=NewElement;
 87         }
 88     }
 89 }
 90 void DestroyTable(HashTable H) //销毁散列表
 91 {
 92     Position h,p,q;
 93     int i;
 94     for(i=0;i<H->TableSize;i++)
 95     {
 96         h=H->TheLists[i];
 97         p=h->Next;
 98         while(p)
 99         {
100             q=p->Next;
101             if(!q)
102             {
103                 free(p);
104                 p=NULL;
105             }
106             else
107             {
108                 free(p);
109                 p=q;
110             }
111         }
112     }
113 }
114 
115 int Delete(ElementType key,HashTable H) //删除关键字
116 {
117     Position Pos,L,Temp;
118     Pos=H->TheLists[Hash(key,H->TableSize)];
119     L=Pos;
120     while(L!=NULL && L->Next!=NULL && L->Next->Element!=key) //单链表删除比较麻烦,需要遍历,双链表则可借助Find
121     {
122         L=L->Next;
123     }
124     if(L==NULL)
125         return 0;
126     else if(L->Next==NULL)
127         free(L);
128     else
129     {
130         Temp=L->Next;
131         L->Next=L->Next->Next;
132         free(Temp);
133     }
134     return 1;
135 }
136 
137 
138 ElementType Retrieve(Position P) //定位
139 {
140     return P->Element;
141 }
142 
143 void main() //测试程序
144 {
145         Position p;
146 
147         HashTable table=InitializeTable(10);
148 
149 
150         Insert(0,table);
151         Insert(1,table);
152         Insert(81,table);
153         Insert(4,table);
154         Insert(64,table);
155         Insert(25,table);
156         Insert(16,table);
157         Insert(36,table);
158         Insert(9,table);
159         Insert(49,table);
160 
161 
162         p=Find(81,table);
163         if(p==NULL)
164             printf("can‘t find\n");
165         else
166             printf("find %d \n",p->Element);
167 
168         if(Delete(81,table))
169         {
170             printf("Delete 81\n");
171         }
172 
173         p=Find(81,table);
174         if(p==NULL)
175             printf("can‘t find 81\n");
176         else
177             printf("find %d \n",p->Element);
178 
179         DestroyTable(table);
180 }

 

以上是关于分离链接法实现散列表的主要内容,如果未能解决你的问题,请参考以下文章

散列表的分离连接法

解决hash冲突之分离链接法

习题5.11 分离链接法的删除操作函数 (20分)

数据结构—— 散列查找:散列表的性能分析

数据结构--散列(分离链接法解决冲突)

散列表