轉自:http://blog.csdn.net/jdh99node
源碼:程序員
1 /********************************************************************* 2 * 哈希表算法實現 3 * (c)copyright 2013,jdh 4 * All Right Reserved 5 *文件名:main.c 6 *程序員:jdh 7 **********************************************************************/ 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 12 /********************************************************************* 13 * 宏定義 14 **********************************************************************/ 15 16 /********************************************************************* 17 * 數據類型重定義 18 **********************************************************************/ 19 20 #define uint8_t unsigned char 21 #define uint16_t unsigned short 22 #define uint32_t unsigned long 23 24 /********************************************************************* 25 * 哈希表長度 26 **********************************************************************/ 27 28 #define HASH_TABLE_LEN 100 29 30 /********************************************************************* 31 * 數據結構 32 **********************************************************************/ 33 //鏈表節點 34 typedef struct _Link_Node 35 { 36 uint16_t id; 37 uint16_t data; 38 struct _Link_Node *next; 39 }Link_Node,*Link_Node_Ptr; 40 41 //哈希表頭 42 typedef struct _Hash_Header 43 { 44 struct _Link_Node *next; 45 }Hash_Header,*Hash_Header_Ptr; 46 47 /********************************************************************* 48 * 全局變量 49 **********************************************************************/ 50 51 //哈希表 52 Hash_Header_Ptr Hash_Table[HASH_TABLE_LEN]; 53 54 /********************************************************************* 55 * 函數 56 **********************************************************************/ 57 58 /********************************************************************* 59 * 哈希表函數 60 *說明: 61 *1.用哈希函數生成id對應的哈希表中的位置 62 輸入:id 63 返回:位置 64 **********************************************************************/ 65 66 uint8_t hash_func(uint16_t id) 67 { 68 uint8_t pos = 0; 69 70 pos = id % HASH_TABLE_LEN; 71 72 return pos; 73 } 74 75 /********************************************************************* 76 * 初始化節點 77 *返回:結點指針 78 **********************************************************************/ 79 80 Link_Node_Ptr init_link_node(void) 81 { 82 Link_Node_Ptr node; 83 84 //申請節點 85 node = (Link_Node_Ptr) malloc(sizeof(Link_Node)); 86 //初始化長度爲0 87 node->next = NULL; 88 89 return node; 90 } 91 92 /********************************************************************* 93 * 初始化哈希表頭結點 94 *返回哈希表頭結點指針 95 **********************************************************************/ 96 97 Hash_Header_Ptr init_hash_header_node(void) 98 { 99 Hash_Header_Ptr node; 100 101 //申請節點 102 node = (Hash_Header_Ptr) malloc(sizeof(Hash_Header)); 103 //初始化長度爲0 104 node->next = NULL; 105 106 return node; 107 } 108 109 110 /********************************************************************* 111 * 哈希表初始化 112 *說明: 113 *1.初始化哈希表Hash_Table 114 *2.哈希表長度最大不能超過256 115 **********************************************************************/ 116 117 void init_hash_table(void) 118 { 119 uint8_t i = 0; 120 121 for (i = 0;i < HASH_TABLE_LEN;i++) 122 { 123 Hash_Table[i] = init_hash_header_node(); 124 Hash_Table[i]->next = NULL; 125 } 126 } 127 128 /********************************************************************* 129 * 在哈希表增長節點 130 *說明: 131 *1.在哈希表的某個鏈表末增長數據 132 輸入:new_node:新節點 133 **********************************************************************/ 134 135 void append_link_node(Link_Node_Ptr new_node) 136 { 137 Link_Node_Ptr node; 138 uint8_t pos = 0; 139 140 //新節點下一個指向爲空 141 new_node->next = NULL; 142 143 //用哈希函數得到位置 144 pos = hash_func(new_node->id); 145 146 //判斷是否爲空鏈表 147 if (Hash_Table[pos]->next == NULL) 148 { 149 //空鏈表 150 Hash_Table[pos]->next = new_node; 151 } 152 else 153 { 154 //不是空鏈表 155 //獲取根節點 156 node = Hash_Table[pos]->next; 157 158 //遍歷 159 while (node->next != NULL) 160 { 161 node = node->next; 162 } 163 164 //插入 165 node->next = new_node; 166 } 167 } 168 169 /********************************************************************* 170 * 在哈希表查詢節點 171 *說明: 172 *1.知道在哈希表某處的單鏈表中,並開始遍歷. 173 *2.返回的是查詢節點的前一個節點指針.這麼作是爲了作刪除操做. 174 輸入:pos:哈希表數組位置,從0開始計數 175 id:所須要查詢節點的id 176 root:若是是根節點,則*root = 1,不然爲0 177 返回:所需查詢的節點的前一個節點指針,若是是根節點則返回根節點,失敗返回0 178 **********************************************************************/ 179 180 Link_Node_Ptr search_link_node(uint16_t id,uint8_t *root) 181 { 182 Link_Node_Ptr node; 183 uint8_t pos = 0; 184 185 //用哈希函數得到位置 186 pos = hash_func(id); 187 188 //獲取根節點 189 node = Hash_Table[pos]->next; 190 191 //判斷單鏈表是否存在 192 if (node == NULL) 193 { 194 return 0; 195 } 196 197 //判斷是不是根節點 198 if (node->id == id) 199 { 200 //是根節點 201 *root = 1; 202 return node; 203 } 204 else 205 { 206 //不是根節點 207 *root = 0; 208 //遍歷 209 while (node->next != NULL) 210 { 211 if (node->next->id == id) 212 { 213 return node; 214 } 215 else 216 { 217 node = node->next; 218 } 219 } 220 221 return 0; 222 } 223 } 224 225 /********************************************************************* 226 * 在哈希表刪除節點 227 *說明: 228 *1.刪除的不是當前節點,而是當前節點後的一個節點 229 輸入:node:刪除此節點後面的一個節點 230 new_node:新節點 231 **********************************************************************/ 232 233 void delete_link_node(Link_Node_Ptr node) 234 { 235 Link_Node_Ptr delete_node; 236 237 //重定向須要刪除的前一個節點 238 delete_node = node->next; 239 node->next = delete_node->next; 240 241 //刪除節點 242 free(delete_node); 243 delete_node = NULL; 244 } 245 246 /********************************************************************* 247 * 在哈希表刪除根節點 248 輸入:node:根節點 249 **********************************************************************/ 250 251 void delete_link_root_node(Link_Node_Ptr node) 252 { 253 uint8_t pos = 0; 254 255 //用哈希函數得到位置 256 pos = hash_func(node->id); 257 258 //哈希表頭清空 259 if (node != NULL) 260 { 261 Hash_Table[pos]->next = node->next; 262 //刪除節點 263 free(node); 264 node = NULL; 265 } 266 } 267 268 /********************************************************************* 269 * 得到哈希表中全部節點數 270 輸入:node:根節點 271 **********************************************************************/ 272 273 uint16_t get_node_num(void) 274 { 275 Link_Node_Ptr node; 276 uint16_t i = 0; 277 uint16_t num = 0; 278 279 //遍歷 280 for (i = 0;i < HASH_TABLE_LEN;i++) 281 { 282 //獲取根節點 283 node = Hash_Table[i]->next; 284 //遍歷 285 while (node != NULL) 286 { 287 num++; 288 node = node->next; 289 } 290 } 291 292 return num; 293 } 294 295 /********************************************************************* 296 * 從哈希表中得到對應序號的節點 297 *參數:index:序號.從1開始,最大值爲節點總數值 298 * root:若是是根節點,則*root = 1,不然爲0 299 返回:所需查詢的節點的前一個節點指針,若是是根節點則返回根節點,失敗返回0 300 **********************************************************************/ 301 302 Link_Node_Ptr get_node_from_index(uint16_t index,uint8_t *root) 303 { 304 Link_Node_Ptr node; 305 uint16_t i = 0; 306 uint16_t num = 0; 307 308 //遍歷 309 for (i = 0;i < HASH_TABLE_LEN;i++) 310 { 311 //獲取根節點 312 node = Hash_Table[i]->next; 313 //判斷單鏈表是否存在 314 if (node == NULL) 315 { 316 continue; 317 } 318 319 //根節點 320 num++; 321 if (num == index) 322 { 323 //是根節點 324 *root = 1; 325 return node; 326 } 327 328 //遍歷 329 while (node->next != NULL) 330 { 331 num++; 332 if (num == index) 333 { 334 //不是根節點 335 *root = 0; 336 return node; 337 } 338 node = node->next; 339 } 340 } 341 342 return 0; 343 } 344 345 /********************************************************************* 346 * 刪除hash表中全部節點 347 **********************************************************************/ 348 349 void drop_hash() 350 { 351 Link_Node_Ptr node; 352 uint16_t i = 0; 353 Link_Node_Ptr node_next; 354 355 //遍歷 356 for (i = 0;i < HASH_TABLE_LEN;i++) 357 { 358 //獲取根節點 359 node = Hash_Table[i]->next; 360 361 while (1) 362 { 363 //判斷單鏈表是否存在 364 if (node == NULL) 365 { 366 //不存在 367 Hash_Table[i]->next = NULL; 368 break; 369 } 370 371 //根節點下一個節點 372 node_next = node->next; 373 //刪除根節點 374 free(node); 375 //重指定根節點 376 node = node_next; 377 } 378 } 379 } 380 381 /********************************************************************* 382 * 輸出全部節點 383 **********************************************************************/ 384 385 void printf_hash() 386 { 387 Link_Node_Ptr node; 388 uint8_t root = 0; 389 uint8_t i = 0; 390 uint8_t num = 0; 391 392 printf("-------------打印hash表-------------\n"); 393 394 num = get_node_num(); 395 for (i = 1;i <= num;i++) 396 { 397 node = get_node_from_index(i,&root); 398 if (node != 0) 399 { 400 if (root) 401 { 402 printf("根節點:節點號%d,id爲%d\n",i,node->id); 403 } 404 else 405 { 406 printf("普通節點:節點號%d,id爲%d\n",i,node->next->id); 407 } 408 } 409 } 410 } 411 412 /********************************************************************* 413 * 主函數 414 *說明:實現對哈希表的新建,創建節點,查詢及增長,刪除節點的操做 415 **********************************************************************/ 416 417 int main() 418 { 419 Link_Node_Ptr node; 420 uint8_t temp = 0; 421 uint8_t root = 0; 422 uint8_t i = 0; 423 424 init_hash_table(); 425 426 //插入數據id = 1,data = 2; 427 node = init_link_node(); 428 node->id = 1; 429 node->data = 2; 430 append_link_node(node); 431 432 //查詢節點數 433 printf("1節點數爲%d\n",get_node_num()); 434 435 node = init_link_node(); 436 node->id = 100; 437 node->data = 101; 438 append_link_node(node); 439 440 node = init_link_node(); 441 node->id = 1002; 442 node->data = 1001; 443 append_link_node(node); 444 445 node = init_link_node(); 446 node->id = 10000; 447 node->data = 10001; 448 append_link_node(node); 449 450 node = init_link_node(); 451 node->id = 1000; 452 node->data = 10001; 453 append_link_node(node); 454 455 node = init_link_node(); 456 node->id = 2; 457 node->data = 10001; 458 append_link_node(node); 459 460 //查詢節點數 461 printf("2節點數爲%d\n",get_node_num()); 462 463 //查詢id = 1000; 464 node = search_link_node(100,&temp); 465 if (node != 0) 466 { 467 if (temp == 0) 468 { 469 printf("刪除普通節點:所需查詢id的值爲%d,數據爲%d\n",node->next->id,node->next->data); 470 471 //刪除 472 delete_link_node(node); 473 } 474 else 475 { 476 //根節點 477 printf("刪除根節點所需查詢id的值爲%d,數據爲%d\n",node->id,node->data); 478 479 //刪除 480 delete_link_root_node(node); 481 } 482 } 483 else 484 { 485 printf("查詢失敗\n"); 486 } 487 488 //查詢id = 1000; 489 node = search_link_node(1001,&temp); 490 if (node != 0) 491 { 492 if (temp == 0) 493 { 494 printf("所需查詢id的值爲%d\n",node->next->data); 495 } 496 else 497 { 498 //根節點 499 printf("所需查詢id的值爲%d\n",node->data); 500 } 501 } 502 else 503 { 504 printf("查詢失敗\n"); 505 } 506 507 //查詢節點數 508 printf("節點數爲%d\n",get_node_num()); 509 510 printf_hash(); 511 512 513 getchar(); 514 return 0; 515 }