众所周知,哈希表是一种时间复杂度低的查找方式,而它的实现原理也比较简单。
举个简单的例子,如果我报一个字:中,让你去找到这个字在字典里的位置,你会怎么做?
首先,我们知道,这个字念:zhong,故我们采取拼音查字法,找到声母:zh,然后再去这个声母下找到韵母:ong,接着,就可以根据zhong这个音所标识的页码,去字典里找到这个字了。
哈希查找,就是一种这样的方法。
字典里的字茫茫多,如果采用最原始的遍历查找法,就如同让你从第一页第一个字开始,一直遍历到你所需要的字为止,这显然是非常浪费时间的。而哈希表,就如同字典前面的拼音检字表和部首检字表。它把元素按照一定的规律(H(key))分类存储于一张“哈希表”中,当我们需要查找某个元素时,就可以通过它的特征,快速找到我们需要的元素。
当然,正如同我们中文里有很多同音字,采取拼音检字表必然会有好几个不同的字,采用同一个音所占据的页面的情况一样,哈希表也不可避免的会出现不同元素的哈希值相同的情况,故,业界也采用了各种各样的方案,来规避这种影响。比如对哈希值相同的元素,再次使用哈希函数等。而本文,我们将采用一中一劳永逸的方法,这种方法也类似于字典。我们把哈希值相同的元素,放入了一个以hash[ i ]为首地址的链表中,这样找到哈希值后就可以直接遍历快速筛选出我们要查找的元素。
接下来我们用代码实现
hash.h文件
/*********************************************/
#ifndef __HASH_H__
#define __HASH_H__
#define N 10 //数组长度
#define P 13 //哈希表
typedef int datatype;
typedef struct Node //定义链表
{
datatype data;//数据域
struct Node *next; //指针域
}Node;
//初始化哈希表
void init_hash(Node *hash[]);
//将元素存入哈希表
int insert_hash(Node *hash[], int x);
//定义查看哈希表函数
void show_hash(Node *hash[]);
//定义哈希查找函数
void search_hash(Node *hash[], int key);
#endif
首先要初始化哈希表
//初始化哈希表
void init_hash(Node *hash[])
{
for(int i=0; i<P; i++)
{
hash[i] = NULL;
}
printf("初始化成功\n");
}
接下来,我们要把元素存入哈希表
//将元素存入哈希表
int insert_hash(Node *hash[], int x)
{
int index = x%P; //定位存储的链表
//封装x进节点
Node *q = (Node*)malloc(sizeof(Node));
if(NULL == q) //判断是否申请节点成功
{
printf("申请失败\n");
return -1;
}
q->data = x;
q->next =NULL;
//使用头插法,节点入链表
q->next = hash[index];
//存储第一个元素时,因为hash[index]是NULL,故等价于q->next = NULL
hash[index] = q; //现在hash[index]里是一个指向NULL的q
//相当于把头节点替换成q
}
定义查看哈希表函数
//定义查看哈希表函数
void show_hash(Node *hash[])
{
for(int i=0; i<P; i++)
{
printf("%d:", i);
Node *q = hash[i]; //定义遍历哈希表
while(q!=NULL)
{
printf("%d->",q->data);
q = q->next;
}
printf("NULL\n");
}
}
这样,我们就完成一张哈希表,也能查看哈希表内的数值了
然就是哈希表最重要的功能:查找。不过其实也不难就是了
//定义哈希查找函数
void search_hash(Node *hash[], int key) //哈希表与值
{
int index = key%P; //定位值所在的链表
//定义遍历指针遍历哈希表
Node *q = hash[index];
while(q!=NULL && q->data!=key)
{
q=q->next;
}
//对找到的节点判断
if(NULL==q)
{
printf("查找失败\n");
}else
{
printf("查找成功\n");
}
}
主函数内容,就交给你们自己实现啦