开放定址法实现散列表
使用分离链接法实现散列表时需要额外的空间来存储指针,而且需要给新单元动态分配空间,导致算法的速度减慢。开放定址法一次分配表的大小,可以使用线性散列,平方散列,双重散列等等方法,这些方法除了散列函数不相同之外,对于散列表的大小要求也不一样。平方散列需要使表的大小是存储元素的两倍以上,这样总能找到空槽来存放产生冲突的元素。(算法导论上有详细证明。)
下面程序使用的是平方探测散列:
头文件:
1 /* 2 * hash.h 3 * 4 * Created on: Dec 12, 2016 5 * Author: csf 6 */ 7 8 #ifndef HASH_H_ 9 #define HASH_H_ 10 11 #define MAXTABLESIZE 200 12 #define MINTABLESIZE 1 13 14 typedef unsigned int Index; 15 typedef Index Position; 16 typedef int ElementType; 17 18 struct HashTbl; 19 typedef struct HashTbl *HashTable; 20 21 int IsPrime(int x); 22 int NextPrime(int y); 23 int Hash(ElementType key,int TableSize); 24 HashTable InitializeTable(int TableSize); 25 void DestroyTable(HashTable H); 26 Position Find(ElementType key,HashTable H); 27 void Insert(ElementType key,HashTable H); 28 ElementType Retrieve(Position P,HashTable H); 29 int Delete(ElementType key,HashTable H); 30 HashTable Rehash(HashTable H); 31 32 #endif /* HASH_H_ */ 33 34 enum KindOfEntry {Legitimate,Empty,Deleted}; 35 36 struct HashEntry 37 { 38 ElementType Element; 39 enum KindOfEntry Info; 40 }; 41 42 typedef struct HashEntry Cell; 43 44 struct HashTbl 45 { 46 int TableSize; 47 Cell *TheCells; 48 };
源文件:
1 /* 2 * hash.c 3 * 4 * Created on: Dec 12, 2016 5 * Author: csf 6 */ 7 8 #include "hash.h" 9 #include "stdio.h" 10 #include "stdlib.h" 11 12 int IsPrime(int x) //判断素数 13 { 14 int i; 15 for(i=2;i*i<x;i++){ 16 if(x%i==0) 17 return 0; 18 } 19 return 1; 20 } 21 22 int NextPrime(int y) //查找最邻近素数 23 { 24 while(1){ 25 if(IsPrime(y)) 26 return y; 27 else 28 y++; 29 } 30 } 31 32 int Hash(ElementType key,int TableSize) //简单取余数的散列函数 33 { 34 return key%TableSize; 35 } 36 37 HashTable InitializeTable(int TableSize) //初始化散列表 38 { 39 HashTable H; 40 int i; 41 42 if(TableSize<MINTABLESIZE) 43 return NULL; 44 45 H=(struct HashTbl*)malloc(sizeof(struct HashTbl)); 46 H->TableSize=NextPrime(TableSize); 47 if(H==NULL) 48 return NULL; 49 H->TheCells=malloc(sizeof(Cell)*H->TableSize); 50 if(H->TheCells==NULL) 51 return NULL; 52 for(i=0;i<H->TableSize;i++) 53 { 54 H->TheCells[i].Info=Empty; 55 } 56 return H; 57 } 58 59 Position Find(ElementType key,HashTable H) //查找表内元素,没有该元素返回空槽 60 { 61 Position Pos; 62 int i; 63 64 i=0; 65 Pos=Hash(key,H->TableSize); 66 while(H->TheCells[Pos].Info!=Empty && H->TheCells[Pos].Element!=key)//字符串比较用strcmp 67 { 68 i+=1; 69 Pos=Pos+2*i-1; 70 if(Pos>=H->TableSize) 71 Pos-=H->TableSize; 72 } 73 return Pos; 74 } 75 76 77 void Insert(ElementType key,HashTable H) //插入新元素,元素存在则什么也不做 78 { 79 Position Pos; 80 Pos=Find(key,H); 81 if(H->TheCells[Pos].Info!=Legitimate) 82 { 83 H->TheCells[Pos].Info=Legitimate; 84 H->TheCells[Pos].Element=key; 85 } 86 } 87 88 void DestroyTable(HashTable H) //销毁散列表 89 { 90 free(H->TheCells); 91 free(H); 92 } 93 94 ElementType Retrieve(Position P,HashTable H) //根据元素位置得到元素值 95 { 96 return H->TheCells[P].Element; 97 } 98 99 int Delete(ElementType key,HashTable H) //删除元素,实际只是把元素标记为deleted 100 { 101 Position TempPos,Pos; 102 int i; 103 104 i=0; 105 Pos=Hash(key,H->TableSize); 106 TempPos=Pos; 107 108 if(H->TheCells[Pos].Element!=key) 109 { 110 i+=1; 111 Pos+=2*i-1; 112 if(Pos>H->TableSize) 113 Pos-=H->TableSize; 114 if(TempPos==Pos) 115 return 0;//没有找到该元素,退出避免死循环 116 } 117 H->TheCells[Pos].Info=Deleted; 118 return 1; 119 } 120 121 HashTable Rehash(HashTable H) //再散列,当填充因子大于0.5或者发生冲突无法找到空槽时使用 122 { 123 int i,OldSize; 124 Cell *OldCells; 125 126 OldSize=H->TableSize; 127 OldCells=H->TheCells; 128 129 H=InitializeTable(2*OldSize); 130 131 for(i=0;i<OldSize;i++) 132 { 133 if(OldCells[i].Info==Legitimate) 134 Insert(OldCells[i].Element,H); 135 } 136 free(OldCells); 137 return H; 138 } 139 140 void main() //测试用例 141 { 142 Position p; 143 144 HashTable table=InitializeTable(30); 145 146 147 Insert(0,table); 148 Insert(1,table); 149 Insert(81,table); 150 Insert(4,table); 151 Insert(64,table); 152 Insert(25,table); 153 Insert(16,table); 154 Insert(36,table); 155 Insert(9,table); 156 Insert(49,table); 157 158 159 p=Find(81,table); 160 printf("%d \n",table->TheCells[p].Element); 161 162 163 if(Delete(81,table)) 164 { 165 printf("Deleted\n"); 166 } 167 168 if(Delete(100,table)) 169 { 170 printf("NoData\n"); 171 } 172 173 DestroyTable(table); 174 }