哈希表实现(C语言)

哈希表概念

哈希表(Hash Table)是一种数据结构,它通过哈希函数来存储和检索键值对(key-value pairs)。哈希表能够提供快速的插入、删除和查找操作,其时间复杂度平均情况下接近常数时间,即 O(1)。

哈希表原理

哈希表的工作原理主要涉及以下几个核心概念:

  1. 哈希函数:哈希表使用哈希函数将键转换成数组索引。理想情况下,哈希函数应该能够将不同的键均匀分布到数组的不同位置,以减少冲突。
  2. 数组:哈希表的底层是一个数组,数组的每个槽位(slot)可以存储一个或多个键值对。
  3. 冲突解决:由于哈希函数可能会将不同的键映射到同一个索引,这种现象称为冲突。解决冲突的方法有多种,包括:
    • 链表法:在数组的每个槽位上维护一个链表,所有映射到同一索引的键值对都存储在链表中。
    • 开放寻址法:当发生冲突时,寻找数组中的下一个空槽位来存储键值对。
    • 双重哈希法:使用第二个哈希函数来决定冲突时的探测序列。
  4. 操作
    • 插入:通过哈希函数计算键的索引,然后将键值对存储在相应的位置。
    • 查找:使用哈希函数找到键的索引,然后在对应的位置检索键值对。
    • 删除:找到键的索引,然后从对应的位置删除键值对。

哈希表用途

哈希表在计算机科学和软件工程中有广泛的应用,以下是一些常见的用途:

  1. 字典和数据库索引:哈希表用于实现字典数据结构,允许快速查找、插入和删除操作,这对于数据库索引尤其重要。
  2. 缓存:在缓存系统中,哈希表用于快速检索存储的数据项,以减少访问延迟。
  3. 唯一性检查:哈希表可以用来检查集合中的元素是否唯一,例如在处理字符串时检查是否有重复的单词。
  4. 数据压缩:在哈希表的基础上,可以构建用于数据压缩的算法,如哈夫曼编码。
  5. 分布式系统:在分布式系统中,哈希表用于实现一致性哈希算法,以优化数据分布和负载均衡。
  6. 查找表:在许多算法中,哈希表用作查找表,以快速判断某个元素是否存在于集合中。
    通过以上原理和用途的介绍,我们可以看到哈希表是一种非常高效和实用的数据结构,它在现代计算机科学中扮演着重要的角色。

代码实现

#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是哈希表的大小
}
  1. 创建哈希表:为哈希表分配内存,并初始化每个桶。
// 定义哈希表节点结构体
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;
}
  1. 插入键值对:将键值对插入到哈希表中,如果发生冲突,则使用链表来解决。
// 插入键值对到哈希表
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;
}
  1. 查找键值对:根据键在哈希表中查找对应的值。
// 根据键在哈希表中查找对应的值
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
}
  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;
    }
}
  1. 销毁哈希表:释放哈希表占用的内存。
// 销毁哈希表
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"具有相同的哈希值。然后,它搜索了所有的键,并删除了一个键值对。最后,它销毁了哈希表。
请注意,这个例子是一个简单的实现,没有处理所有可能的边缘情况,如内存不足、空指针等。在实际应用中,你可能需要添加更多的错误检查和异常处理。

你可能感兴趣的:(数据结构,数据结构)