引子

当构造数组变得不实用或困难,尤其又要增删查找时。一种动态集合结构(至少支持INSERT、SEARCH和DELETE等字典操作)就被恨恨期待了——散列表就是一种实现字典操作的数据结构。

1. 初识哈希表

[[哈希]]表(Hash Table,又称散列表),可根据关键字(key)直接访问的数据结构。哈希表通过哈希函数把关键字映射到表中的一个位置,存储位置与关键字间产生一种对应关系 h ,使得每个 key 对应一个存储位置f(key)。查找时根据给定的关键字 key,通过f(key)确定包含key的记录在存储空间中的位置。

3. C语言实现

/*
 *@create: 2024-02-04
 *@authro: jytang@stu.ecnu.edu.cn
 *@descri: Hash Table实现
*/
/*---------- 头文件 -----------*/
#include <string.h>
/*---------- 宏定义 -----------*/
#define FAILURE (-1)
#define TRUE    (0)
#define FALSE   (1)
/*--------- 数据结构 ----------*/
typedef struct {
    char *key;
    int value;
    struct HashNode *next;
} HashNode;  // 哈希表节点

typedef struct {
    int tableSize;
    HashNode **table;
} HashTable;  // 哈希表结构
/*----------函数定义-----------*/
/*
 *@descri: 哈希函数
 *@parame: IN *key --键值
           IN table_size --哈希表大小
 *@return: 哈希值
*/
unsigned int HashFunction(const char *key, int table_size)
{
    unsigned int hash = 0;
    while (*key) {
        hash = (hash * 31) + *key;
        key++;
    }
    return hash % table_size;
}
/*
 *@descri: 创建哈希表
 *@parame: IN size --哈希表大小
 *@return: 哈希表指针
*/
HashTable *HashTable_Create(int size)
{
    HashTable *hashTable = (HashTable *)malloc(sizeof(HashTable));
    hashTable->tableSize = size;
    hashTable->table = (HashNode **)calloc(size, sizeof(HashNode *));
    return hashTable;
}
/*
 *@descri: 数据入槽
 *@parame: IN *hashTable --哈希表指针
 *@parame: IN *key --键值
 *@parame: IN size --哈希表大小
 *@return: 哈希表指针
*/
void HashTable_Insert(HashTable *hashTable, const char *key, int size)
{
    unsigned int index = HashFunction(key, hashTable->tableSize);
    HashNode *newNode = (HashNode *)malloc(sizeof(HashNode));
    newNode->key = _strdup(key);
    newNode->value = size;
    newNode->next = NULL;
    newNode->next = hashTable->table[index];
    hashTable->table[index] = newNode;
}
/*
 *@descri: 查找哈希表
 *@parame: IN *hashTable --哈希表指针
 *@parame: IN *key --键值
 *@return: 哈希表指针
*/
int HashTable_Search(HashTable *hashTable, const char *key)
{
    unsigned int index = HashFunction(key, hashTable->tableSize);
    HashNode *current = hashTable->table[index];
    while (current != NULL) {
        if (strcmp(current->key, key) == 0) {
            return current->value;
        }
        current = current->next;
    }
    return FAILURE;
}
/*
 *@descri: 数据出槽
 *@parame: IN *hashTable --哈希表指针
 *@parame: IN *key --键值
 *@return: 哈希表指针
*/
void HashTable_RemoveItem(HashTable *hashTable, const char *key)
{
    unsigned int index = HashFunction(key, hashTable->tableSize);
    HashNode *current = hashTable->table[index];
    HashNode *prev = NULL;
    // 遍历链表查找键
    while (current != NULL && strcmp(current->key, key) != 0) {
        prev = current;
        current = current->next;
    }
    // 如果找到键,删除节点
    if (current != NULL) {
        if (prev != NULL) {
            prev->next = current->next;
        } else {
            hashTable->table[index] = current->next;
        }
        free(current->key);
        free(current);
    }
}
/*
 *@descri: 销毁哈希表
 *@parame: IN *hashTable --哈希表指针
*/
void HashTable_Destroy(HashTable *hashTable)
{
    free(hashTable->table);
    free(hashTable);
}
/*
 *@descri: test
*/
int main(void)
{
    HashTable *hashTable = HashTable_Create(10);
    HashTable_Insert(hashTable, "apple", 5);
    HashTable_Insert(hashTable, "banana", 3);
    HashTable_Insert(hashTable, "orange", 8);
    printf("Value for key 'apple': %d\n", HashTable_Search(hashTable, "apple"));
    printf("Value for key 'banana': %d\n", HashTable_Search(hashTable, "banana"));
    printf("Value for key 'orange': %d\n", HashTable_Search(hashTable, "orange"));
    // 删除键为 "banana" 的节点
    HashTable_RemoveItem(hashTable, "banana");
    // 测试是否成功删除
    printf("Value for key 'banana': %d\n", HashTable_Search(hashTable, "banana"));
    HashTable_Destroy(hashTable);
  return 0;
}

参考

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐