之前一直采用链表的方式存储数据,但是在实际应用中发现若链表长度太长且要经常查找数据时程序反应会比较慢,这是由于链表查找效率比较低,后来发现一种比较高效的链表查找方式——哈希表。哈希表为可通过关键字查找数据的数组,数据(关键字k)可通过某种关系(映射函数,也叫散列表,例如:y = f(k))存储在数组中,我们根据关键字就可在数组中查找到数据。若对于不同的关键字可得到到相同的值即k1!=k2, f(k1)==f(k2)成为碰撞或冲突。解决冲突的方法有很多如开放寻址法、再散列法、拉链法等,本文采用拉链法解决冲突。将某个一维数组全部元素都作为链表头,关键字通过映射(本文采用的是求余取模法,当然还有其他的方法可供选择)可得到数组中链表头部地址,创建一个节点,将该关键字存放到节点中,并将该节点插入到刚才找到的链表中去。
节点数据结构:typedef struct node{
struct node *next;
TypeKey data;
}Node;
链表头数据结构:typedef struct hashtbale{
Node *head;
unsigned int size; //哈希表中关键字个数
TypeKey mode; //哈希表长度,即模
}Hash;
下面是对哈希表的操作:
(1)初始化
void InitHash(Hash *hash, unsigned int size)
{
int i = 0;
hash->size = 0;
hash->mode = size;
hash->head = (Node *)malloc(sizeof(Node)*size);
if(hash->head == NULL)
exit(0);
for(i=0; i<hash->mode; i++){
hash->head[i].data = i;
hash->head[i].next = NULL;
}
}
(2)插入关键字
void InsertKey(Hash *hash, TypeKey key)
{
int add = key%hash->mode;
Node *node = (Node *)malloc(sizeof(Node));
node->next = hash->head[add].next;
node->data = key;
hash->head[add].next = node;
hash->size ++;
}
(3)删除某个关键字
char DeletKey(Hash *hash, TypeKey key)
{
int add = key%hash->mode;
Node *p;
Node *q;
p = hash->head[add].next;
if(p == NULL){
printf("no such key");
return -1;
}
if(p->data == key){
hash->head[add].next = p->next;
p->next = NULL;
free(p);
hash->size --;
return 0;
}
q = p;
p = p->next;
while(p != NULL){
if(p->data == key){
q->next = p->next;
p->next = NULL;
free(p);
hash->size --;
return 0;
}
p = p->next;
q = q->next;
}
printf("no such key \n");
return -1;
}
(4)打印哈希表
void PrintHash(Hash hash)
{
int i = 0;
Node *p;
Node *q;
if(hash.head == NULL){
printf("hashtable is null \n");
return ;
}
for(i=0; i<hash.size; i++){
printf("keyMode %d : \t",hash.head[i].data);
p = hash.head[i].next;
q = p;
while(p != NULL){
printf("%d ",p->data);
p = p->next;
if(hash.head+i == p){
break;
}
}
printf("\r\n");
}
}
(5)测试函数
int main()
{
int i = 0;
Hash hash;
TypeKey key[30] = {1, 52, 63, 96, 32 ,23, 64, 12, 210, 45, 57, 21, 36,
55, 87, 123, 46, 62, 93, 82, 85, 86, 74, 73, 39, 38, 20,
30, 43, 100};
memset(&hash, 0, sizeof(hash));
//创建一个哈希表,长度为10
InitHash(&hash, 10);
for(i=0; i<30; i++){
InsertKey(&hash, key[i]);
}
InsertKey(&hash, 111);
PrintHash(hash);
}
此外还有哈希表的清空与删除,可根据上述代码编写出来,不再罗列。