hash table相關

哈希表的C實現(一)

 

哈希表(Hash table,也叫散列表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。具體的介紹網上有很詳細的描述,如閒聊哈希表 ,這裏就不再累述了;

哈希表在像Java、C#等語言中是與生俱來的。可是在C的世界中,似乎只有自己動手,豐衣足食;在網上google了一把,大致有幾個版本,我會一一來分析對比;

首先先來交代一下哈希表實現中需要注意的一些概念:

(主要參考:這裏

  1. 哈希函數

也叫散列函數,即:根據key,計算出key對應記錄的儲存位置
position = f(key)

散列函數滿足以下的條件:

1、對輸入值運算,得到一個固定長度的摘要(Hash value);

2、不同的輸入值可能對應同樣的輸出值;

以下的函數都可以認爲是一個散列函數:

f(x) = x mod 16; (1)

f(x) = (x2 + 10) * x; (2)

f(x) = (x | 0×0000FFFF) XOR (x >> 16); (3)

不過,僅僅滿足上面這兩條的函數,作爲散列函數,還有不足的地方。我們還希望散列函數滿足下面幾點:

1、散列函數的輸出值儘量接近均勻分佈;

2、x的微小變化可以使f(x)發生非常大的變化,即所謂“雪崩效應”(Avalanche effect);

上面兩點用數學語言表示,就是:

1, 輸出值y的分佈函數F(y)=y/m, m爲散列函數的最大值。或記爲y~U[0, m]

2,|df(x)/dx| >> 1;

從上面兩點,大家看看,前面舉例的三個散列函數,哪個更好呢?對了,是第三個:

f(x) = (x | 0×0000FFFF) XOR (x >> 16);

它很完美地滿足“好的散列函數”的兩個附加條件。

2、哈希衝突(Hash collision)

也就是兩個不同輸入產生了相同輸出值的情況。首先,哈希衝突是無法避免的,因此,哈希算法的選擇直接決定了哈希衝突發送的概率;同時必須要對哈希衝突進行處理,方法主要有以下幾種:

1, 鏈地址法

鏈地址法:對Hash表中每個Hash值建立一個衝突表,即將衝突的幾個記錄以表的形式存儲在其中

2, 開放地址法

下面就來看看每種方法的具體實現吧:

鏈地址法:

舉例說明: 設有 8 個元素 { a,b,c,d,e,f,g,h } ,採用某種哈希函數得到的地址分別爲: {0 , 2 , 4 , 1 , 0 , 8 , 7 , 2} ,當哈希表長度爲 10 時,採用鏈地址法解決衝突的哈希表如下圖所示。 

圖片及舉例引自:這裏


複製代碼
  1 #include "stdafx.h"
2 #include <string.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 typedef struct _node{
7 char *name;
8 char *desc;
9 struct _node *next;
10 }node;
11
12 #define HASHSIZE 101
13 static node* hashtab[HASHSIZE];
14
15 void inithashtab(){
16 int i;
17 for(i=0;i<HASHSIZE;i++)
18 hashtab[i]=NULL;
19 }
20
21 unsigned int hash(char *s){
22 unsigned int h=0;
23 for(;*s;s++)
24 h=*s+h*31;
25 return h%HASHSIZE;
26 }
27
28 node* lookup(char *n){
29 unsigned int hi=hash(n);
30 node* np=hashtab[hi];
31 for(;np!=NULL;np=np->next){
32 if(!strcmp(np->name,n))
33 return np;
34 }
35
36 return NULL;
37 }
38
39 char* m_strdup(char *o){
40 int l=strlen(o)+1;
41 char *ns=(char*)malloc(l*sizeof(char));
42 strcpy(ns,o);
43 if(ns==NULL)
44 return NULL;
45 else
46 return ns;
47 }
48
49 char* get(char* name){
50 node* n=lookup(name);
51 if(n==NULL)
52 return NULL;
53 else
54 return n->desc;
55 }
56
57 int install(char* name,char* desc){
58 unsigned int hi;
59 node* np;
60 if((np=lookup(name))==NULL){
61 hi=hash(name);
62 np=(node*)malloc(sizeof(node));
63 if(np==NULL)
64 return 0;
65 np->name=m_strdup(name);
66 if(np->name==NULL) return 0;
67 np->next=hashtab[hi];
68 hashtab[hi]=np;
69 }
70 else
71 free(np->desc);
72 np->desc=m_strdup(desc);
73 if(np->desc==NULL) return 0;
74
75 return 1;
76 }
77
78 /* A pretty useless but good debugging function,
79 which simply displays the hashtable in (key.value) pairs
80 */
81 void displaytable(){
82 int i;
83 node *t;
84 for(i=0;i<HASHSIZE;i++){
85 if(hashtab[i]==NULL)
86 printf("()");
87 else{
88 t=hashtab[i];
89 printf("(");
90 for(;t!=NULL;t=t->next)
91 printf("(%s.%s) ",t->name,t->desc);
92 printf(".)");
93 }
94 }
95 }
96
97 void cleanup(){
98 int i;
99 node *np,*t;
100 for(i=0;i<HASHSIZE;i++){
101 if(hashtab[i]!=NULL){
102 np=hashtab[i];
103 while(np!=NULL){
104 t=np->next;
105 free(np->name);
106 free(np->desc);
107 free(np);
108 np=t;
109 }
110 }
111 }
112 }
113
114 main(){
115 int i;
116 char* names[]={"name","address","phone","k101","k110"};
117 char* descs[]={"Sourav","Sinagor","26300788","Value1","Value2"};
118
119 inithashtab();
120 for(i=0;i<5;i++)
121 install(names[i],descs[i]);
122
123 printf("Done");
124 printf("If we didnt do anything wrong..""we should see %s",get("k110"));
125
126 install("phone","9433120451");
127
128 printf("Again if we go right, we have %s and %s",get("k101"),get("phone"));
129
130 /*displaytable();*/
131 cleanup();
132 return 0;
133 }
複製代碼

轉自http://www.cnblogs.com/xiekeli/archive/2012/01/13/2321207.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章