之前在写过的很多的结构中都实现过搜索功能,但是不论是顺序搜索还是搜索二叉树,由于元素的存储位置和元素各关键码之间没有对应的关系,所以在查找一个元素的时候必须要经过关键码的多次比较。因此搜索的时间复杂度很难能够达到O(1)。
解决哈希冲突的方法:闭散列和开散列
6 //我们此处的Hash表希望存储的数据是键值对这样的结构
7 #define HashMaxSize 1000
8 typedef int KeyType;
9 typedef int ValueType;
10 typedef size_t (*HashFunc)(KeyType key);
11
12 typedef enum
13 {
14 Empty,//空状态
15 Valid,//有效状态
16 Delete,//被删改的状态
17 }Stat;
18
19 //这个结构体表示Hash表中的一个元素,这个元素中同时包含了键值对
20 typedef struct HashElem
21 {
22 KeyType key;
23 ValueType value;
24 Stat stat;
25 }HashElem;
26
27 //[0,size)这个区间就不能表示Hash表中有效元素的区间
28 typedef struct HashTable
29 {
30 HashElem data[HashMaxSize];
31 size_t size;
32 HashFunc func;//这是一个函数指针,指向一个Hash函数
33 }HashTable;
34
11 void HashInit(HashTable* hashtable,HashFunc hash_func)
12 {
13 hashtable->size = 0;
14 hashtable->func = hash_func;
15 size_t i = 0;
16 for(;i < HashMaxSize; ++i)
17 {
18 hashtable->data[i].stat = Empty;
19 }
20 return ;
21 }
22
23 void HashDestroy(HashTable* hashtable)
24 {
25 hashtable->size = 0;
26 hashtable->func = NULL;
27 size_t i = 0;
28 for(;i < HashMaxSize; ++i)
29 {
30 hashtable->data[i].stat = Empty;
31 }
32 return ;
33 }
(4)若发现key相同的元素,则认为插入失败
35 void HashInsert(HashTable* hashtable,KeyType key,ValueType value)
36 {
37 if(hashtable == NULL)
38 {
39 //非法操作
40 return ;
41 }
42 //1.判定hash表是否能继续插入(根据负载因子判定)
43 //此处只是把负载因子定义为0.8
44 if(hashtable->size >= 0.8*HashMaxSize)
45 {
46 //发现当前的hash表已达到负载因子的上限,此时直接插入失败
47 return ;
48 }
49 //2.根据key来计算offset
50 size_t offset = hashtable->func(key);
51 //3.从offset位置开始线性的往后查找,找到第一个状态为empty的元素进行插入
52 while(1)
53 {
54 if(hashtable->data[offset].stat == Empty)
55 {
56 //此时找到合适的位置放置要插入的元素
57 hashtable->data[offset].stat = Valid;
58 hashtable->data[offset].key = key;
59 hashtable->data[offset].value = value;
60 //5.++size
61 ++hashtable->size;
62 return ;
63 }
64 else if(hashtable->data[offset].stat == Valid && hashtable->data[offset].key == key)
65 {
66 //4.若发现key相同的元素,此时认为插入失败
67 //hash表中存在了一个key相同的元素
68 //认为插入失败
69 //若要修改value的值就放开下面这行代码
70 //hashtable->data[offset].value = value;
71 return ;
72 }
73 else
74 {
75 ++offset;
76 if(offset >= HashMaxSize)
77 {
78 offset = 0;
79 }
80 }
81 }
82 return ;
83 }
85 int HashFind(HashTable* hashtable,KeyType key,ValueType* value)
86 {
87 if(hashtable == NULL || value == NULL)
88 {
89 return 0;
90 }
91 if(hashtable->size == 0)
92 {
93 //空hash表
94 return 0;
95 }
96 //1.根据key计算出offset
97 size_t offset = hashtable->func(key);
98 //2.从offset开始往后查找,每次取到一个元素,使用key进行比较
99 while(1)
100 {
101 if(hashtable->data[offset].key == key && hashtable->data[offset].stat == Valid)
102 {
103 //找到了
104 //a)找到了key相同的元素,此时直接返回value,认为查找成功
105 *value = hashtable->data[offset].value;
106 return 1;
107 }
108 else if(hashtable->data[offset].stat == Empty)
109 {
110 //查找失败
111 //b)发现当前key不相同,就继续往后查找
112 return 0;
113 }
114 else
115 {
116 //c)若发现当前元素为NULL,认为查找失败
117 ++offset;
118 offset = offset>= HashMaxSize?0:offset;
119 }
120 }
121 return 0;
122 }
123
5.哈希表的删除操作
124 void HashRemove(HashTable* hashtable,KeyType key)
125 {
126 if(hashtable == NULL)
127 {
128 return ;
129 }
130 if(hashtable->size == 0)
131 {
132 return ;
133 }
134 //1.根据key计算offset
135 size_t offset = hashtable->func(key);
136 //2.从offset开始依次判断当前元素的key和要删除的key是不是相同
137 while(1)
138 {
139 if(hashtable->data[offset].key == key && hashtable->data[offset].stat == Valid)
140 {
141 //a)若当前的key就是要删除的key,删除当前元素即可,删除元素要引入一个新的状态标记Delete
142 //找到了要删除的元素,要标记成 Delete
143 hashtable->data[offset].stat = Delete;
144 --hashtable->size;
145 return ;
146 }
147 else if(hashtable->data[offset].stat == Empty)
148 {
149 //b)若当前元素为NULL,key在hash表查找删除失败
150 //删除失败
151 return ;
152 }
153 else
154 {
155 //c)剩下的情况++offset,线性的探测下一个元素
156 ++offset;
157 offset = offset >= HashMaxSize?0:offset;
158 }
159 }
160 return ;
161 }