哈希表

来源:互联网 发布:c 获取mac物理地址 编辑:程序博客网 时间:2024/05/18 01:54

哈希表,又称为散列,是一种更加快捷的查找技术。我们之前的查找,都是这样一种思路:集合中拿出来一个元素,看看是否与我们要找的相等,如果不等,缩小范围,继续查找。而哈希表是完全另外一种思路:当我知道key值以后,我就可以直接计算出这个元素在集合中的位置,根本不需要一次又一次的查找!是不是很神奇呢?其实一点也不神奇,举一个例子就明白了,假如我的数组A中,第i个元素里面装的key就是i,那么数字3肯定是在第3个位置,数字10肯定是在第10个位置。这不是废话么……哈希表就是利用利用这种基本的思想,建立一个从key到位置的函数,然后进行直接计算查找。

但是实际应用中,和可能出现一种问题:就是多个key被映射成为同一个位置。比如:我想用人的名字来映射人的时候,就会出现两个人的名字汉语拼音相同的情况。那么这种情况又该如何处理你?有两种大的思路:

1.建立一个缓冲区,把凡是拼音重复的人放到缓冲区中。当我通过名字查找人时,出现找的不对,就在缓冲区里找。

2.进行再探测。就是在其他地方查找。探测的方法也可以有很多种。

(1)在找到查找位置的index的index-1,index+1位置查找,index-2,index+2查找,依次类推。这种方法称为线性再探测。

(2)在查找位置index周围随机的查找。称为随机在探测。

(3)再哈希。就是当冲突时,采用另外一种映射方式来查找。

基本思想就是这么多,下面我们看看程序:

#include <stdio.h>#include <malloc.h>typedef struct HashTable{char* data;int count;int size;}HashTable,*pHashTable;extern  int counter;bool initHashTable(pHashTable  ,int );void destroyHashTable(pHashTable );void fillHashTable(pHashTable  ,char* , int );int Hash(char );bool HashSerach(pHashTable , char , int* );


 

#include "hash.h"bool initHashTable(pHashTable pH ,int n){pH->count = 0;pH->size = n;pH->data = (char*)malloc(sizeof(char) * n);//起始值为NULLfor(int i = 0; i < n;++i){pH->data[i] = '*';}if(NULL == pH->data)return false;elsereturn true;}void destroyHashTable(pHashTable pH){pH->count = 0;pH->size = 0;free(pH->data);pH->data= NULL;}//Hash函数就是简单地取模int Hash(char key){return (int)key % 7;}void fillHashTable(pHashTable pH ,char* key, int n){int tmp;for(int i = 0; i < n; ++i){tmp = Hash(key[i]);//如果这个位置没有人用过,那么就把键填过去if('*' == pH->data[tmp])pH->data[tmp] = key[i];else{//直到找到一个没人用过的位置while('*' != pH->data[tmp]){//跳过7个位置,再次判断有没有被使用tmp = (tmp + 7) % pH->size;//防止越界}//如果没有,则把值填过去pH->data[tmp] = key[i];}++pH->count;}}//使用全局变量来记录运算次数int counter = 0;bool HashSerach(pHashTable pH, char key, int* index){int tmp = Hash(key);//直接找到++counter;if(pH->data[tmp] == key){*index = tmp;return true;}else{while(true){//增加7个元素,再次尝试tmp += 7;++counter;if(pH->data[tmp] == key){*index = tmp;return true;}//tmp越界,表明没有找到if(tmp > 30){*index = -1;return false;}}}}


最后看看主函数:

#include "hash.h"int main(void){HashTable h;initHashTable(&h,30);char test = 'a';char arr[26];for(int i = 0; i< 26;++i){arr[i] = test + i;}fillHashTable(&h,arr,26);for(int i = 0; i < h.size;++i)printf("%c",h.data[i]);printf("\n");int index = 100;for(int i = 0; i < 26;++i){HashSerach(&h,test+i,&index);if(index >= 0)printf("find %c\n",h.data[index]);elseprintf("can't find the char");}printf("总的查找次数为%d",counter);destroyHashTable(&h);return 0;}


 

这个程序中是通过取模来模拟查找到重复元素的过程。对待重复元素的方法就是再哈希:对当前key的位置+7。最后,可以通过全局变量来判断需要查找多少次。我这里通过依次查找26个英文字母的小写计算的出了总的查找次数。显然,当总的查找次数/查找的总元素数越接近1时,哈希表更接近于一一映射的函数,查找的效率更高。

原创粉丝点击