C语言数据结构哈希表详解

C语言数据结构哈希表详解

什么是哈希表?

哈希表(Hash Table)是一种采用散列函数(hash函数)将数据映射到一个固定长度的数组中,并且以 O(1) 的时间复杂度进行数据插入、查找、删除操作的数据结构。哈希表主要由以下三个组成部分构成:
- 数组:用于存储映射到对应下标上的数据。
- 散列函数:将数据映射到数组下标上的规则。
- 冲突处理方式:当不同的数据映射到同一下标时,需要采取的处理措施,如开放地址法、链地址法等。

实现哈希表的关键点

哈希表的实现过程中,有以下几个关键点需要掌握:

哈希函数的设计

哈希函数的设计决定了哈希表的效率和数据存储的均衡性,通常需要符合以下要求:
- 易于计算:计算哈希值的时间复杂度要尽量低。
- 均匀分布:将数据散列到数组中的下标需要尽量均匀,减少冲突的发生。
- 低冲突率:哈希算法计算出相同哈希值的输入应尽量少。

哈希表的扩容和缩容

当哈希表存储的数据量达到一定阈值时,需要对哈希表进行扩容,以保证哈希表的效率和空间利用率。同时,当哈希表中存储的数据量变小时,还需要对哈希表进行缩容以减少空间的浪费。

冲突的解决方式

当不同的数据映射到同一下标时,可以采取以下几种冲突解决方式:
- 开放地址法:尝试向其他的空闲位置插入元素,类似于寻找新的住址。
- 链地址法:将多个具有同一哈希值的元素存储在同一个链表中。

哈希表的实现示例

以下是一个使用链地址法实现哈希表的示例,详见代码:

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

// 哈希表节点结构体
typedef struct HashNode {
    char* key;
    char* value;
    struct HashNode* next;
} HashNode;

// 哈希表结构体
typedef struct HashTable {
    HashNode** nodes;
    int size;
} HashTable;

// 创建哈希表
HashTable* createHashTable(int size) {
    HashTable* hashTable = (HashTable*)malloc(sizeof(HashTable));
    hashTable->nodes = (HashNode**)calloc(size, sizeof(HashNode*));
    hashTable->size = size;
    return hashTable;
}

// 计算哈希值
int hash(char* key, int size) {
    unsigned int hashValue = 0;
    for (int i = 0; i < strlen(key); i++) {
        hashValue = hashValue * 31 + key[i];
    }
    return hashValue % size;
}

// 插入键值对
void put(HashTable* hashTable, char* key, char* value) {
    int index = hash(key, hashTable->size);
    HashNode* node = hashTable->nodes[index];
    while (node != NULL) {
        if (strcmp(node->key, key) == 0) {
            // 如果键已经存在,更新其对应的值
            strcpy(node->value, value);
            return;
        }
        node = node->next;
    }
    // 如果键不存在,创建新的节点并插入链表头部
    HashNode* newNode = (HashNode*)malloc(sizeof(HashNode));
    newNode->key = (char*)malloc(strlen(key) + 1);
    strcpy(newNode->key, key);
    newNode->value = (char*)malloc(strlen(value) + 1);
    strcpy(newNode->value, value);
    newNode->next = hashTable->nodes[index];
    hashTable->nodes[index] = newNode;
}

// 获取键对应的值
char* get(HashTable* hashTable, char* key) {
    int index = hash(key, hashTable->size);
    HashNode* node = hashTable->nodes[index];
    while (node != NULL) {
        if (strcmp(node->key, key) == 0) {
            return node->value;
        }
        node = node->next;
    }
    return NULL;
}

// 删除键值对
void removeByKey(HashTable* hashTable, char* key) {
    int index = hash(key, hashTable->size);
    HashNode* node = hashTable->nodes[index];
    HashNode* preNode = NULL;
    while (node != NULL) {
        if (strcmp(node->key, key) == 0) {
            if (preNode == NULL) {
                // 如果删除的节点是链表的第一个节点,需要将链表头部指向第二个节点
                hashTable->nodes[index] = node->next;
            } else {
                // 如果删除的节点不是链表的第一个节点,需要将前一个节点指向下一个节点
                preNode->next = node->next;
            }
            free(node->key);
            free(node->value);
            free(node);
            return;
        }
        preNode = node;
        node = node->next;
    }
}

// 删除哈希表
void deleteHashTable(HashTable* hashTable) {
    for (int i = 0; i < hashTable->size; i++) {
        HashNode* node = hashTable->nodes[i];
        while (node != NULL) {
            HashNode* nextNode = node->next;
            free(node->key);
            free(node->value);
            free(node);
            node = nextNode;
        }
    }
    free(hashTable->nodes);
    free(hashTable);
}

// 示例:使用哈希表存储学生信息
int main() {
    HashTable* studentTable = createHashTable(100);
    put(studentTable, "Tom", "20");
    put(studentTable, "Jerry", "19");
    put(studentTable, "Alice", "21");
    put(studentTable, "Bob", "18");

    printf("Bob's age is %s\n", get(studentTable, "Bob"));

    removeByKey(studentTable, "Alice");

    printf("Alice's age is %s\n", get(studentTable, "Alice"));

    deleteHashTable(studentTable);
    return 0;
}

在上述代码中,我们使用了链地址法解决了哈希冲突,并实现了插入、查找、删除等操作。此外,我们还根据实际需求,将该哈希表用于存储学生信息,以便更好地说明哈希表的应用场景。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言数据结构哈希表详解 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月16日

相关文章

  • 【ACM算法竞赛日常训练】DAY4题解与分析【树】【子序列】| 组合数学 | 动态规划

    DAY4共2题: 树(组合数学) 子序列(dp,数学) ? 作者:Eriktse? 简介:19岁,211计算机在读,现役ACM银牌选手?力争以通俗易懂的方式讲解算法!❤️欢迎关注我,一起交流C++/Python算法。(优质好文持续更新中……)?? 原文链接(阅读原文获得更好阅读体验):https://www.eriktse.com/algorithm/109…

    算法与数据结构 2023年4月18日
    00
  • Java数据结构BFS广搜法解决迷宫问题

    Java数据结构BFS广搜法解决迷宫问题 什么是BFS广搜法? 广度优先搜索(BFS)是一种遍历或搜索数据结构(例如树或图)的算法经典方法之一,也是解决迷宫问题的有效解法之一。BFS方法是从图的某个节点出发,以广度优先的方式依次访问与该节点相通的各节点,直到访问所有节点。BFS算法主要借助队列的数据结构来实现。 解决迷宫问题的具体实现 数据准备: 在解决迷宫…

    数据结构 2023年5月17日
    00
  • Java数据结构的十大排序

    Java数据结构的十大排序攻略 简介 在计算机科学中,排序算法是一种将一串数据按照特定顺序进行排列的方法,其中常见的排序算法有很多种,不同的算法适用于不同的数据类型和数据规模。Java是一种常见的编程语言,也提供了很多实现排序算法的类和方法。 本文将介绍Java数据结构的十大排序算法,分别为:插入排序、希尔排序、选择排序、冒泡排序、快速排序、归并排序、堆排序…

    数据结构 2023年5月17日
    00
  • c++ 数据结构map的使用详解

    c++ 数据结构map的使用详解 什么是map map是C++ STL中提供的一种用以存储键值对(key-value)的容器。它能够以平均O(log n)复杂度进行搜索、插入、删除操作,并且保持元素顺序,是一种比较高效的数据结构。 map的基本用法 定义map 定义map需要包含头文件<map>。 语法:map<key_type, valu…

    数据结构 2023年5月17日
    00
  • JavaScript的Set数据结构详解

    JavaScript中的Set数据结构详解 什么是Set? Set 是一种 Javascript 内置的数据结构。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set 本身是一个构造函数,可以通过new关键字来创建 Set 数据结构。 let mySet = new Set(); Set的基本用法 Set实例对象有以下常用方法: add(value):…

    数据结构 2023年5月17日
    00
  • C语言数据结构与算法时间空间复杂度基础实践

    C语言数据结构与算法时间空间复杂度基础实践攻略 基本概念 时间复杂度:算法在执行时所需要的基本操作数,通常用O(n)表示,其中n是输入数据的规模。时间复杂度越小,算法执行所需要的时间越少,算法效率越高。 空间复杂度:算法在执行时所需要的额外空间数,通常用O(S)表示,其中S是额外的空间数。空间复杂度越小,所需的额外空间越少,算法的内存效率越高。 实践步骤 1…

    数据结构 2023年5月17日
    00
  • C语言 数据结构之数组模拟实现顺序表流程详解

    C语言 数据结构之数组模拟实现顺序表流程详解 什么是顺序表? 顺序表是一种基于连续存储结构的数据结构,它可以用一段连续的存储单元来存储线性表中的所有元素。 顺序表的实现思路 顺序表的实现主要依赖数组。我们可以定义一个数组来存储线性表的数据元素,同时再定义一个变量来保存线性表当前的长度。当需要对线性表进行插入、删除、查找等操作时,根据需求,可以通过数组的下标来…

    数据结构 2023年5月17日
    00
  • C语言数据结构顺序表中的增删改(尾插尾删)教程示例详解

    C语言数据结构顺序表中的增删改(尾插尾删)教程示例详解 什么是顺序表 顺序表是一种线性表,它通过一块连续的存储空间来存储数据。顺序表中的数据元素排列在物理存储空间上也是连续的,每个元素占用一个固定的位置和大小,并且使用下标来访问。 顺序表的定义 下面是以int类型为例的一个简单顺序表的定义: #define SIZE 50 typedef struct { …

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部