《数据结构-C语言实现散列表(Hash)》

散列表(Hash Table),也叫哈希表或散列映射,是一种非常常见的数据结构。它的实现原理是通过将键(key)映射到一个固定的位置(也叫哈希地址)来实现快速查找。

在 C 语言中,实现散列表主要有两个步骤:散列函数的设计和冲突解决方法的实现。以下是详细的说明:

  1. 散列函数的设计

散列函数是将键映射到哈希表中的位置的算法。散列函数应该尽可能均匀地分布键的值,并且应该将键映射到哈希表的不同位置上,以避免冲突。以下是一个示例散列函数:

这个散列函数采用了一种称为 djb2 的算法,它将字符串中的每个字符乘以一个常数(33),并将它们相加。这个算法被证明在实践中非常有效,因为它在计算时保持了良好的随机性和分布性。其中 size 参数是哈希表的大小,需要根据实际需求来确定。

     2.冲突解决方法的实现

由于散列函数可能将不同的键映射到相同的哈希地址上,所以需要实现一种冲突解决方法来解决这个问题。以下是两种常见的冲突解决方法:

  • 链式法(Chaining):每个哈希地址上维护一个链表,当键映射到相同的哈希地址时,将其插入到链表的末尾。插入和查找的复杂度均为 O(1),但需要额外的空间来维护链表。
  • 开放地址法(Open Addressing):当键映射到相同的哈希地址时,根据某种规则(如线性探测法、二次探测法等)在哈希表中寻找下一个可用的位置,直到找到一个空闲的位置或者遍历完整个哈希表。插入和查找的复杂度也为 O(1),但可能会造成哈希表的聚集现象,即某些哈希地址上的元素过多,造成性能下降。

以下是链式法的实现示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TABLE_SIZE 100

// 散列表中的元素
typedef struct {
    char* key;
    int value;
} HashElement;

// 散列表
typedef struct {
    HashElement** elements;
    int size;
} HashTable;

// 创建一个新的散列表
HashTable* createHashTable() {
    HashTable* table = (HashTable*)malloc(sizeof(HashTable));
    table->elements = (HashElement**)calloc(TABLE_SIZE, sizeof(HashElement*));
    table->size = TABLE_SIZE;
    return table;
}

// 释放散列表中的所有元素
void freeHashTable(HashTable* table) {
    for (int i = 0; i < table->size; i++) {
        HashElement* element = table->elements[i];
        if (element != NULL) {
            free(element->key);
            free(element);
        }
    }
    free(table->elements);
    free(table);
}

// 计算散列值
int hashFunction(char* key) {
    int hash = 0;
    for (int i = 0; i < strlen(key); i++) {
        hash = (hash * 31 + key[i]) % TABLE_SIZE;
    }
    return hash;
}

// 在散列表中插入一个元素
void insertElement(HashTable* table, char* key, int value) {
    int hash = hashFunction(key);
    HashElement* element = (HashElement*)malloc(sizeof(HashElement));
    element->key = strdup(key);
    element->value = value;
    table->elements[hash] = element;
}

// 在散列表中查找一个元素
int findElement(HashTable* table, char* key) {
    int hash = hashFunction(key);
    HashElement* element = table->elements[hash];
    if (element != NULL && strcmp(element->key, key) == 0) {
        return element->value;
    } else {
        return -1;
    }
}

int main() {
    HashTable* table = createHashTable();
    insertElement(table, "apple", 10);
    insertElement(table, "banana", 20);
    insertElement(table, "orange", 30);
    printf("apple = %d\n", findElement(table, "apple"));
    printf("banana = %d\n", findElement(table, "banana"));
    printf("orange = %d\n", findElement(table, "orange"));
    freeHashTable(table);
    return 0;
}

在上面的代码中,我们首先定义了一个HashElement结构体,表示散列表中的元素,包含一个键和一个值。然后定义了一个HashTable结构体,表示散列表本身,包含一个元素指针数组和一个大小。createHashTable函数用于创建一个新的散列表,分配内存并初始化元素指针数组。freeHashTable函数用于释放

散列表中的所有元素,包括键和值。hashFunction函数用于计算散列值,采用了一个简单的散列算法,即将每个字符的ASCII码乘以一个质数31,并将结果相加。insertElement函数用于向散列表中插入一个元素,计算键的散列值并将元素指针存储在相应的散列表位置中。findElement函数用于在散列表中查找一个元素,根据键的散列值定位元素并比较键的值是否相等。

在主函数中,我们首先创建一个新的散列表,然后向散列表中插入三个元素。最后,我们使用findElement函数查找每个键的值,并打印结果。注意,在本例中,我们假设键是字符串,但是在实际应用中,键可以是任何类型,只要可以计算散列值并进行比较即可。

总的来说,散列表是一种非常有用的数据结构,可以在常数平均时间内进行插入、查找和删除操作。在C语言中,可以使用指针和动态内存分配来实现散列表。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Like_Bamboo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值