开放定址法:
(1) 线性探测法:逐个探测每个单元(必要时绕回)以查找出一个空单元。典型的冲突函数
F(i)= i;
缺点: 容易产生一次聚集(primary clustering);
(2) 平方探测法:典型的冲突函数是:F(i) = i2,消除线性探测一次聚集的冲突解决办法。
缺点:容易产生二次聚集(secondary clustering);
定理:使用平方探测,且表的大小为素数,那么当表至少一半空的时候,总能够插入一个新元具体详细介绍见资源:http://download.csdn.net/detail/johnnyhu90/6191597 一书的117页介绍
下面代码示例:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
/***********************************************************/
// 程序名称:HashSearch_3.cpp // 程序目的:哈希表之---分离链接散列法 // 程序来源:数据结构与算法分析(C语言描述) P-120 // 日期:2013-9-1 12:50:33 JohnnyHu修改 /***********************************************************/ #include #include #define Error( str ) FatalError( str ) #define FatalError( str ) fprintf( stderr, "%s\n", str ), exit( 1 ) #define MinTableSize 5 #define NUMITEMS 5 typedef int ElementType; typedef unsigned int Index; typedef Index Position; struct hashTbl; typedef struct hashTbl* HashTable; Index Hash(ElementType key, int tableSize); HashTable InitializeTable( int tableSize); Position Find(ElementType key, HashTable h); void Insert(ElementType key, HashTable h); ElementType Retrieve(Position p, HashTable h); void DestroyTable(HashTable h); HashTable Rehash(HashTable h); void PrintfTable(HashTable h); enum kindOfEntry {legitmate, empty, deleted}; // 合法的、空、删除的 struct hashEntry { ElementType element; enum kindOfEntry info; }; typedef struct hashEntry Cell; struct hashTbl { int tableSize; Cell* theCells; }; int main( void) { HashTable hashTable; int currentSize; hashTable = InitializeTable(currentSize = 7); // 当前哈希表的大小为13 int insertedNum = 0; // 标识插入表中元素个数 for ( int i = 0, j = 1; i < NUMITEMS; i++, j += 2) { if( i > currentSize / 2 ) { hashTable = Rehash( hashTable ); // 再散列 printf( "插入元素数超过: %d, Rehashing(再散列)...\n" , i); currentSize *= 2; } Insert(j, hashTable); insertedNum++; } printf( "输出哈希表中数据: \n"); PrintfTable(hashTable); int keyValue; printf( "输入要插入的(int)值(-1则退出输入操作):"); scanf( "%d", &keyValue); while (- 1 != keyValue) { if( insertedNum > currentSize / 2 ) { hashTable = Rehash( hashTable ); // 再散列 printf( "插入元素数超过: %d, Rehashing(再散列)...\n" , insertedNum); currentSize *= 2; } Insert(keyValue, hashTable); insertedNum++; printf( "输入要插入的(int)值(-1则退出输入操作):"); scanf( "%d", &keyValue); } printf( "执行插入后的哈希表数据:\n"); PrintfTable(hashTable); // 检测各个值 Position pos; for ( int i= 0, j= 1; i < NUMITEMS; i++, j += 2) { if ( Retrieve((pos = Find(j, hashTable)), hashTable) != j ) printf( "在%d处出错!\n", j); } printf( "程序执行完毕!\n"); DestroyTable(hashTable); // 释放内存空间 return 0; } /************************************************************************/ // 返回下一个素数(与n仅接着的素数) /************************************************************************/ static int NextPrime( int n) { int i; if( n % 2 == 0 ) n++; for( ; ; n += 2 ) { for( i = 3; i * i <= n; i += 2 ) { if( n % i == 0 ) goto ContOuter; /* Sorry about this! */ } return n; ContOuter: ; } } /************************************************************************/ // 哈希函数 /************************************************************************/ Index Hash(ElementType key, int tableSize) { return key % tableSize; } /************************************************************************/ // 初始化哈希表 /************************************************************************/ HashTable InitializeTable( int tableSize) { if (tableSize < MinTableSize) { Error( "要创建的表太小!"); return NULL; } HashTable h; h = (HashTable)malloc( sizeof( struct hashTbl)); if ( NULL == h) FatalError( "内存分配失败!"); h->tableSize = NextPrime(tableSize); // 哈希表大小是素数 h->theCells = (Cell*)malloc( sizeof(Cell) * h->tableSize); if ( NULL == h->theCells) FatalError( "给数组内存分配失败!"); for ( int i = 0; i < h->tableSize; i++) h->theCells[i].info = empty; return h; } /************************************************************************/ // 哈希表查找 /************************************************************************/ Position Find(ElementType key, HashTable h) { Position correntPos; int collisionNum; collisionNum = 0; correntPos = Hash(key, h->tableSize); while (h->theCells[correntPos].info != empty && h->theCells[correntPos].element != key) { // 这里进行平方探测 correntPos += 2 * ++collisionNum - 1; if (correntPos >= h->tableSize) correntPos -= h->tableSize; } return correntPos; } /************************************************************************/ // 哈希表插入 /************************************************************************/ void Insert(ElementType key, HashTable h) { Position pos; pos = Find(key, h); if (h->theCells[pos].info != legitmate) { h->theCells[pos].info = legitmate; h->theCells[pos].element = key; } } /************************************************************************/ // 开放定址列表再散列 /************************************************************************/ HashTable Rehash(HashTable h) { int oldSize; Cell* oldCells; oldCells = h->theCells; oldSize = h->tableSize; // 获得新的空表 h = InitializeTable( 2 * oldSize); for ( int i = 0; i < oldSize; i++) { if (oldCells[i].info == legitmate) Insert(oldCells[i].element, h); } free(oldCells); return h; } /************************************************************************/ // 获取键值 /************************************************************************/ ElementType Retrieve(Position p, HashTable h) { return h->theCells[p].element; } /************************************************************************/ // 哈希表销毁 /************************************************************************/ void DestroyTable(HashTable h) { free(h->theCells); free(h); return; } /************************************************************************/ // Fuction:打印哈希表 // target: 测试哈希表中数据 // Author: Johnny Hu // Date: 2013-9-1 6:36:38 /************************************************************************/ void PrintfTable(HashTable h) { Cell* printCells; printCells = h->theCells; for ( int i= 0; i < h->tableSize; i++) { if (printCells[i].info == legitmate) printf( "hashtable[%d]: [%d]\n", i, printCells[i].element); else if (printCells[i].info == empty) printf( "hashtable[%d]: [ ]\n", i); } } |