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日

相关文章

  • 算法总结–ST表

    声明(叠甲):鄙人水平有限,本文为作者的学习总结,仅供参考。 1. RMQ 介绍 在开始介绍 ST 表前,我们先了解以下它以用的场景 RMQ问题 。RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ…

    算法与数据结构 2023年4月18日
    00
  • redis中的数据结构和编码详解

    Redis中的数据结构和编码详解 Redis中的数据结构 Redis支持以下五种数据结构: 字符串(string):最基本的数据类型,Redis中的字符串是二进制安全的,意味着您可以在字符串中存储任何数据。例如,您可以将图像文件或序列化对象存储为Redis字符串。字符串最大可以容纳512MB。 列表(list):Redis列表是字符串列表,其中的元素按照插入…

    数据结构 2023年5月17日
    00
  • C++数据结构与算法之判断一个链表是否为回文结构的方法

    当我们遇到判断一个链表是否为回文结构的问题时,可以考虑使用如下的方法: 遍历链表,将链表节点的值存储到一个数组或者栈中。 遍历链表,将链表节点的值与前面存储的值进行比较,如果全部相同,则证明链表为回文结构。 下面是详细的代码实现和示例说明: 实现 首先,我们需要定义一个链表节点的结构体,包括节点值和指向下一个节点的指针: struct ListNode { …

    数据结构 2023年5月17日
    00
  • 数据结构之数组翻转的实现方法

    下面是数据结构之数组翻转的实现方法的详细攻略。 1. 问题描述 在数组中,将元素以轴对称的方式进行翻转,即将数组的第一个元素和最后一个元素交换,第二个元素和倒数第二个元素交换,以此类推。 例如,对于数组[1, 2, 3, 4, 5],经过翻转后变成[5, 4, 3, 2, 1]。 2. 解法讲解 2.1 方法一:双指针法 双指针法是常用的一种方法,可以实现两…

    数据结构 2023年5月17日
    00
  • 图计算引擎分析–GridGraph

    作者:京东科技 李永萍 GridGraph:Large-Scale Graph Processing on a Single Machine Using 2-Level Hierarchical Partitioning 图计算框架 图计算系统按照计算方式划分可分为:单机内存图处理系统,单机核外图处理系统,分布式内存图处理系统,分布式核外图处理系统。本文将详…

    算法与数据结构 2023年4月20日
    00
  • C++数据结构之AVL树的实现

    C++数据结构之AVL树的实现 什么是AVL树 AVL树是一种自平衡二叉查找树,也就是说它通过旋转操作来保持树的平衡。 在AVL树中,任何节点的两个子树高度差不超过1。如果高度差大于1,则需要通过旋转操作来调整树的平衡。 AVL树提供了比红黑树更快的插入和删除操作,但是在读取数据时红黑树更快。 AVL树的实现 结构体定义 我们可以先定义一个结构体来表示AVL…

    数据结构 2023年5月17日
    00
  • C++实现数据结构的顺序表详解

    C++实现数据结构的顺序表详解 介绍 在进行程序开发时,常常需要对数据进行存储和操作。其中一种数据结构是顺序表,它提供了一种在内存中线性存储数据的方法,能够方便地对数据进行插入、删除、查找等操作。本文将详细介绍如何使用C++实现数据结构的顺序表,帮助读者掌握顺序表的创建、插入、删除、查找等操作。 创建顺序表 顺序表可以使用数组来实现。下面的代码展示了如何创建…

    数据结构 2023年5月17日
    00
  • C语言程序设计第五版谭浩强课后答案(第二章答案)

    首先,需要说明的是本题涉及到一个特定的知识领域,即C语言程序设计,以及该领域内某个具体教材的课后习题解答。因此,本攻略的重心将放在如何利用Markdown格式对该领域内的知识进行准确、清晰的表达和展示上。 下面是本攻略的目录: C语言程序设计第五版谭浩强课后答案(第二章答案)攻略 一、简介 二、题目列表 三、示例说明 示例一 示例二 四、总结 一、简介 本攻…

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