哈希表(Hash Table)是一种数据结构,它通过哈希函数来存储和检索键值对(key-value pairs)。哈希表能够提供快速的插入、删除和查找操作,其时间复杂度平均情况下接近常数时间,即 O(1)。
哈希表的工作原理主要涉及以下几个核心概念:
哈希表在计算机科学和软件工程中有广泛的应用,以下是一些常见的用途:
#include
#include
#include
#define TABLE_SIZE 10 // 哈希表的大小
// 简单的哈希函数,将字符串的每个字符的ASCII值相加
unsigned int hashFunction(const char* key) {
unsigned int hash = 0;
while (*key) {
hash += *key++;
}
return hash % TABLE_SIZE; // TABLE_SIZE是哈希表的大小
}
// 定义哈希表节点结构体
typedef struct HashNode {
char* key; // 键
int value; // 值
struct HashNode* next; // 指向下一个具有相同哈希值的节点
} HashNode;
// 创建哈希表
HashNode* createHashTable() {
HashNode* table = (HashNode*)malloc(TABLE_SIZE * sizeof(HashNode));
for (int i = 0; i < TABLE_SIZE; i++) {
table[i].key = NULL;
table[i].value = 0;
table[i].next = NULL;
}
return table;
}
// 插入键值对到哈希表
void insertHashTable(HashNode* table, const char* key, int value) {
unsigned int index = hashFunction(key); // 计算键的哈希值
HashNode* newNode = (HashNode*)malloc(sizeof(HashNode)); // 为新节点分配内存
newNode->key = strdup(key); // 复制键
newNode->value = value; // 设置值
newNode->next = table[index].next; // 将新节点插入到链表的头部
table[index].next = newNode;
}
// 根据键在哈希表中查找对应的值
int searchHashTable(HashNode* table, const char* key) {
unsigned int index = hashFunction(key); // 计算键的哈希值
HashNode* node = table[index].next; // 获取链表的头部
while (node != NULL) {
if (strcmp(node->key, key) == 0) {
return node->value; // 找到键,返回对应的值
}
node = node->next; // 移动到链表的下一个节点
}
return -1; // 未找到键,返回-1
}
// 从哈希表中删除指定的键值对
void deleteHashTable(HashNode* table, const char* key) {
unsigned int index = hashFunction(key); // 计算键的哈希值
HashNode* node = table[index].next; // 获取链表的头部
HashNode* prev = &table[index]; // 记录前一个节点
while (node != NULL) {
if (strcmp(node->key, key) == 0) {
prev->next = node->next; // 从链表中移除节点
free(node->key); // 释放键的内存
free(node); // 释放节点的内存
return;
}
prev = node;
node = node->next;
}
}
// 销毁哈希表
void destroyHashTable(HashNode* table) {
for (int i = 0; i < TABLE_SIZE; i++) {
HashNode* node = table[i].next;
while (node != NULL) {
HashNode* temp = node;
node = node->next;
free(temp->key); // 释放键的内存
free(temp); // 释放节点的内存
}
}
free(table); // 释放哈希表的内存
}
现在,让我们使用上述代码来创建一个哈希表,并执行插入、查找和删除操作,特别是演示如何处理哈希冲突。
int main() {
HashNode* table = createHashTable(); // 创建哈希表
// 插入具有相同哈希值的键值对,以演示哈希冲突的解决
insertHashTable(table, "apple", 5);
insertHashTable(table, "banana", 7);
insertHashTable(table, "cherry", 3);
insertHashTable(table, "apricot", 8); // "apricot"和"apple"具有相同的哈希值
printf("搜索 'apple': %d\n", searchHashTable(table, "apple")); // 查找键值对
printf("搜索 'banana': %d\n", searchHashTable(table, "banana"));
printf("搜索 'cherry': %d\n", searchHashTable(table, "cherry"));
printf("搜索 'apricot': %d\n", searchHashTable(table, "apricot")); // 查找具有相同哈希值的键值对
deleteHashTable(table, "banana"); // 删除键值对
printf("搜索 'banana': %d\n", searchHashTable(table, "banana")); // 再次查找
destroyHashTable(table); // 销毁哈希表
return 0;
}
这段代码创建了一个哈希表,并插入了四个键值对,其中"apple"和"apricot"具有相同的哈希值。然后,它搜索了所有的键,并删除了一个键值对。最后,它销毁了哈希表。
请注意,这个例子是一个简单的实现,没有处理所有可能的边缘情况,如内存不足、空指针等。在实际应用中,你可能需要添加更多的错误检查和异常处理。