C语言实现哈希表
简介:
哈希表在根据内容查找时,它的时间复杂度相对于要逐一遍历的数组或者链表要小。
散列算法:主要由md5(消息摘要算法),sha1(安全散列) ,这两者不可靠。sha2(安全散列2 sha256/512)目前还没冲突,较为可靠。
散列冲突:多个数据,进行散列之后的散列值相同,此时会存在散列冲突。
常见的解决方法:有线性探测、平方探测、二次散列、链表分离、链表分离改良实现(链表+红黑树)。
该程序:采用链表分离的方法解决散列冲突。适合初学者学习。
该图为本程序的图解,结合此图看程序时有对哈希表有较好的理解。
//sanlie.c 哈希表的实现
//采用链表的方式
//遇到散列冲突时,采用链表分离的方式
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//哈希表中数据元素的结构体
typedef struct
{
char *key; //关键字
char *value;
} Element;
//数据元素单链表
typedef struct Node
{
Element student; //数据元素
struct Node *next; //next指针
} Node;
//哈希表
typedef struct
{
Node *head; //数据元素存储
int size; //当前表中的大小,表长
int count; //哈希表中的数据元素的个数
} HashTable;
//初始化哈希表
HashTable *inittable(int tablesize)
{
HashTable *table = (HashTable *)malloc(sizeof(HashTable));
table->size = tablesize;
//分配和初始化单链表数据元素的头结点
table->head = (Node *)malloc((table->size) * sizeof(Node));
memset(table->head, 0, sizeof(Node) * (table->size));
table->count = 0; //现有的元素的个数
return table;
}
//哈希函数
int hash(HashTable *table, char *key)
{
int sum = 0; //字符串的ASNI之和
for (int i = 0; i < strlen(key); i++)
{
sum += key[i];
}
return sum % table->size;
}
//在哈希表中查找关键字
Node *find(HashTable *table, char *key)
{
int ii = hash(table, key);
Node *node = table->head[ii].next;
//遍历单链表
while ((node != NULL) && (node->student.key != key))
{
node = node->next;
}
return node;
}
//往哈希表中插入元素
int put(HashTable *table, char *key, char *value)
{
//从哈希表中查找元素
Node *ee = find(table, key);
if (ee != NULL)
{
printf("元素已经存在。\n");
return 0;
}
int ii = hash(table, key);
Node *node = (Node *)malloc(sizeof(Node));
node->student.key = key;
node->student.value = value;
//追加在对应位置的头结点后面
node->next = table->head[ii].next;
table->head[ii].next = node;
table->count++;
return 1;
}
//遍历哈希表
void Print(HashTable *table)
{
for (int i = 0; i < table->size; i++)
{
Node *node = table->head[i].next;
while (node)
{
printf("%s-%s ", node->student.key, node->student.value);
node = node->next;
}
printf("\n");
}
printf("\n");
}
//从哈希表中删除元素
int get(HashTable *table, char *key)
{
int ii = hash(table, key);
Node *node = &table->head[ii];
//遍历单链表,node停留在待删除关键结点key的前一结点
while ((node != NULL) && (node->next->student.key != key))
{
node = node->next;
}
if (node->next == NULL)
return 0; //查找失败
Node *tmp = node->next; //tmp为将要删除的结点
node->next = tmp->next;
free(tmp); //释放结点
table->count--;
return 1;
}
int main(int argc, char const *argv[])
{
HashTable *table = inittable(5);
put(table, "alice", "alice info");
put(table, "bob", "bob info");
put(table, "hack", "hack info");
Print(table);
get(table, "bob");
Print(table);
Node *node = find(table, "hack");
if (node != NULL)
printf("找到%s-%s\n", node->student.key, node->student.value);
Node *node1 = find(table, "bob");
if (node1 != NULL)
printf("找到%s-%s\n", node1->student.key, node1->student.value);
return 0;
}