哈希表实验C语言版实现

下面是“哈希表实验C语言版实现”的完整攻略。

一、前置知识

  • C 语言基础
  • 数据结构 - 哈希表

二、哈希表实现原理

哈希表是一种数据结构,是用来存储键值对的,通过计算每个键的哈希值,将键值对存储到一个数组中。哈希表中的每个键值对都根据一个哈希函数映射到一个位置,这个位置就是数据在数组里的下标。哈希表通常具有O(1)的查找时间。

哈希表需要以下几个关键要素:

  • 哈希函数
  • 数组桶(bucket)
  • 冲突解决方法

哈希表实现的核心是哈希函数。哈希函数将键映射到整数,这个整数就是数据在数组里的下标。数组桶存储对应下标的键值对。当出现哈希冲突时,需要用一些方法来解决,比如链表。

三、C 语言版哈希表实现

1. 哈希函数

哈希函数将键映射到整数,可以用一些简单的算法来实现,比如模运算。

unsigned int hash(const char *key, int table_size) {
    unsigned int hashval = 0;
    while (*key != '\0') {
        hashval = *key + 31 * hashval;
        key++;
    }
    return hashval % table_size;
}

这个哈希函数将字符串转换为整数,然后对表大小取模。这样能确保计算出的哈希值不会超出表的范围。

2. 数组桶

在实现哈希表时需要一个数组来存储键值对。下面是数组结构体的定义:

typedef struct {
    char *key;
    int value;
} entry;

typedef struct {
    int size;
    int count;
    entry *entries;
} hashmap;

hashmap结构体中包含一个整数size,表示数组的大小,一个整数count,表示当前哈希表的大小。entries是一个指向entry结构体的指针数组,用来存储键值对。

3. 冲突解决方法

在哈希表中,有时候会出现两个键映射到同一个位置的情况,这就是哈希冲突。解决哈希冲突的方法有很多种,比如链表法和开放地址法。

在链表法中,每个数组下标都存储一个链表,如果出现哈希冲突,就将新的键值对加入链表的末尾。

typedef struct {
    char *key;
    int value;
    struct entry *next;
} entry;

typedef struct {
    int size;
    int count;
    entry **entries;
} hashmap;

entry结构体中,还增加了一个指针next,用来指向下一个键值对。在hashmap结构体中,entries变成了一个指向指针的数组。

4. 完整代码示例

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

typedef struct {
    char *key;
    int value;
    struct entry *next;
} entry;

typedef struct {
    int size;
    int count;
    entry **entries;
} hashmap;

hashmap *create_hashmap(int size) {
    hashmap *map = malloc(sizeof(hashmap));
    map->size = size;
    map->count = 0;
    map->entries = calloc(size, sizeof(entry *));
    return map;
}

unsigned int hash(const char *key, int table_size) {
    unsigned int hashval = 0;
    while (*key != '\0') {
        hashval = *key + 31 * hashval;
        key++;
    }
    return hashval % table_size;
}

entry *create_entry(const char *key, int value) {
    entry *e = malloc(sizeof(entry));
    e->key = strdup(key);
    e->value = value;
    e->next = NULL;
    return e;
}

void insert(hashmap *map, const char *key, int value) {
    int index = hash(key, map->size);
    entry *entries = map->entries[index];
    if (entries == NULL) {
        map->entries[index] = create_entry(key, value);
        map->count++;
    } else {
        while (entries->next != NULL && strcmp(entries->key, key) != 0) {
            entries = entries->next;
        }
        if (strcmp(entries->key, key) == 0) {
            entries->value = value;
        } else {
            entries->next = create_entry(key, value);
            map->count++;
        }
    }
}

int get(hashmap *map, const char *key) {
    int index = hash(key, map->size);
    entry *entries = map->entries[index];
    while (entries != NULL && strcmp(entries->key, key) != 0) {
        entries = entries->next;
    }
    if (entries == NULL) {
        return -1;
    } else {
        return entries->value;
    }
}

void delete(hashmap *map, const char *key) {
    int index = hash(key, map->size);
    entry *entries = map->entries[index], *prev = NULL;
    while (entries != NULL && strcmp(entries->key, key) != 0) {
        prev = entries;
        entries = entries->next;
    }
    if (entries == NULL) {
        return;
    } else {
        if (prev == NULL) {
            map->entries[index] = entries->next;
        } else {
            prev->next = entries->next;
        }
        free(entries->key);
        free(entries);
        map->count--;
    }
}

void print_hashmap(hashmap *map) {
    for (int i = 0; i < map->size; i++) {
        entry *entries = map->entries[i];
        if (entries != NULL) {
            printf("Bucket %d: ", i);
            while (entries != NULL) {
                printf("(%s, %d) ", entries->key, entries->value);
                entries = entries->next;
            }
            printf("\n");
        }
    }
}

int main() {
    hashmap *map = create_hashmap(5);

    insert(map, "key1", 10);
    insert(map, "key2", 20);
    insert(map, "key3", 30);
    insert(map, "key4", 40);

    printf("key1: %d\n", get(map, "key1"));
    printf("key2: %d\n", get(map, "key2"));
    printf("key3: %d\n", get(map, "key3"));
    printf("key4: %d\n", get(map, "key4"));
    printf("key5: %d\n", get(map, "key5"));

    printf("\n");
    print_hashmap(map);

    delete(map, "key1");
    delete(map, "key3");

    printf("\n");
    print_hashmap(map);

    return 0;
}

上面的示例代码中,首先创建了一个大小为5的哈希表,然后插入了4个键值对。接下来,使用get函数获取了每个键的值,再尝试获取一个不存在的键。最后,调用了print_hashmap函数打印哈希表,然后分别删除key1key3键值对,再次打印哈希表。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:哈希表实验C语言版实现 - Python技术站

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

相关文章

  • SpringBoot异步方法捕捉异常详解

    SpringBoot异步方法捕捉异常详解 介绍 SpringBoot提供了一种处理异步方法异常的机制,即AsyncUncaughtExceptionHandler接口。通过这个接口,我们可以自定义异常处理机制,在异步方法抛出异常时进行处理。本文将详细对这个机制进行讲解,并提供两个示例说明。 异步方法抛出异常的问题 在Java中,我们可以使用多线程或者异步方法…

    C 2023年5月23日
    00
  • C语言之双向链表详解及实例代码

    C语言之双向链表详解及实例代码 本文将详细讲解C语言中双向链表的实现原理及实例代码,让读者能够深入理解双向链表的基本概念和用法。 什么是双向链表? 双向链表是一种常见的数据结构,它由多个节点构成,每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点,在实际应用中可以用来存储一系列元素,以股票数据为例,将每支股票的编码和名称存储在一个双向链表中,方便快…

    C 2023年5月24日
    00
  • 使用C语言编写钢琴小程序

    环境配置 安装C语言开发环境,推荐使用gcc编译器。 安装SDL库,SDL是一套跨平台的游戏开发库,可以方便的创建图形界面和音频效果。 在代码中包含SDL库头文件以及链接SDL静态库或者动态库。 构建程序框架 创建一个窗口用于展示钢琴的键盘和播放音频。 定义音符的频率和时长,将每个音符映射到对应的键盘上。 监听键盘事件,根据用户的输入播放相应的音符。 程序实…

    C 2023年5月23日
    00
  • Json数据转换list对象实现思路及代码

    “Json数据转换list对象实现思路及代码”主要是指通过将Json格式的数据转换成List对象,方便对数据进行处理,以下是详细讲解这个过程所需的步骤和代码示例: 1. 引入相关依赖 在转换JSON数据的时候我们需要使用到相关包,通常使用依赖管理工具,比如 Maven / Gradle 来引入相关包,其中常用的包包括: jackson-databind: 提…

    C 2023年5月23日
    00
  • Qt实现闹钟小程序

    下面是实现Qt闹钟小程序的完整攻略: 一、准备工作 下载并安装Qt开发环境。 创建一个Qt Widgets Application项目。 二、设计界面 打开Qt Designer,设计一个闹钟小程序的界面。 添加控件,如标签、文本编辑器、按钮等,用于设置闹钟时间和启动闹钟。 下面是一个示例界面,其中包含一个QLabel用于显示当前时间,两个QSpinBox用…

    C 2023年5月23日
    00
  • C++实现简单信息管理系统

    下面是C++实现简单信息管理系统的完整攻略: 1. 确定需求 在开发信息管理系统之前,我们需要确定所需功能。例如,这个信息管理系统需要哪些模块、哪些操作、需要保存哪些信息等等。只有确定了这些需求之后,才能知道如何实现系统。 2. 设计系统框架 在确定了需求之后,可以开始设计系统框架。系统框架包括模块划分、数据结构设计等。可以使用流程图、UML图等工具来完成系…

    C 2023年5月23日
    00
  • C语言结构体释放问题

    C语言中的结构体是一种自定义的数据类型,相对于其他基本数据类型,结构体可以描述更为复杂的数据结构。在程序中,我们通常需要申请、初始化、使用和释放结构体变量,其中释放结构体变量所占用的内存空间是非常重要的一步。本文将详细讲解C语言结构体释放问题的完整使用攻略,让读者能够正确地使用结构体并避免内存泄漏问题。 申请和释放结构体空间的注意点 在C语言中申请和释放结构…

    C 2023年5月9日
    00
  • U盘双击后无法打开并提示找不到应用程序的原因及解决

    针对“U盘双击后无法打开并提示找不到应用程序”的问题,我们可以进行以下的解决攻略: 原因分析 U盘病毒感染:一些恶意病毒会将U盘上的文件属性进行篡改,导致无法打开并提示找不到应用程序; 应用程序被误删或损坏:在使用U盘的过程中,如果应用程序被误删或者损坏,也会导致U盘双击后无法打开并提示找不到应用程序; U盘上的文件格式不受系统识别:如果U盘上的文件格式不被…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部