哈希表实验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日

相关文章

  • C# Newtonsoft.Json 的使用说明

    C# Newtonsoft.Json是一个常用的Json操作库,使用它可以方便地实现Json格式的数据的序列化与反序列化。下面来详细讲解一下如何使用该库。 1. 安装Newtonsoft.Json 首先需要在项目中安装Newtonsoft.Json库。可以通过Nuget包管理器搜索 “Newtonsoft.Json” 进行安装,也可以从 官方网站 下载安装包…

    C 2023年5月23日
    00
  • python非单一.py文件用Pyinstaller打包发布成exe

    下面是“Python非单一.py文件用Pyinstaller打包发布成exe”的完整攻略。 什么是Pyinstaller PyInstaller是一个Python应用程序的打包工具。它可以将Python程序打包成单个可执行文件,这让你可以方便地将Python程序发布给其他人,而不需要他们安装Python环境。 Pyinstaller的安装 在安装Pyinst…

    C 2023年5月22日
    00
  • SpringBoot使用前缀树过滤敏感词的方法实例

    下面是“SpringBoot使用前缀树过滤敏感词的方法实例”的完整攻略。 一、前缀树概念 前缀树,也称字典树或Trie树,是一种树形数据结构,用于高效地存储和检索字符串数据集。 前缀树的每一个节点都代表一个字符串的前缀,从根节点到每一个叶子节点构成的路径即为一个字符串。除根节点外,每一个节点都有若干个指向其子节点的边,每一条边上都标注有一个字符,代表从父节点…

    C 2023年5月23日
    00
  • java15新功能的详细讲解

    Java 15 新功能的详细讲解攻略 简介 Java 15 是 Java 编程语言的最新版本,于 2020 年 9 月发布。它包含了多项新增功能和改进,如 ZGC 改进、密封类、预览特性、记录类型等。 本攻略将详细介绍 Java 15 的新功能,以及如何使用这些新功能来提高开发人员的效率以及增强代码可读性。 密封类 Java 15 引入了密封类(sealed…

    C 2023年5月23日
    00
  • VSCode添加头文件(C/C++)的实现示例

    下面是VSCode添加头文件的实现攻略: 步骤一:新建C/C++源文件 在VSCode中新建C/C++源文件,你可以通过菜单栏的文件->新建文件,或者使用快捷键Ctrl+N。 步骤二:添加头文件 添加头文件有两种方式: 方式一:手动添加头文件 在新建的C/C++源文件中的代码位置,手动添加头文件引用。例如,如果你想添加stdio.h,可以使用以下代码:…

    C 2023年5月23日
    00
  • C++实现DES加密算法实例解析

    C++实现DES加密算法实例解析 简介 DES(Data Encryption Standard)算法是一种对称加密算法,通常用于保护数据的机密性。与其他加密算法相比,它的优势在于速度快,代码简单,实现成本较低,因此在许多安全应用中广泛使用。 本教程将会详细介绍如何使用C++语言实现DES加密算法,并提供两个示例说明,使读者可以快速掌握DES加密算法的使用方…

    C 2023年5月23日
    00
  • 详解iOS通过ASIHTTPRequest提交JSON数据

    下面是详解iOS通过ASIHTTPRequest提交JSON数据的完整攻略: 1. 准备工作 在使用ASIHTTPRequest来提交JSON数据之前,需要先将ASIHTTPRequest集成到项目中。可以使用CocoaPods或手动下载并导入ASIHTTPRequest文件夹。 2. 导入ASIHTTPRequest头文件 在需要使用ASIHTTPRequ…

    C 2023年5月23日
    00
  • 使用C语言实例描述程序中的内聚和耦合问题

    使用C语言实例描述程序中的内聚和耦合问题可以分为以下步骤: 一、了解内聚和耦合的概念 内聚(cohesion)是指程序模块内部的各个元素(变量、函数等)之间联系的紧密程度,或者说是模块内部元素彼此互相依靠的程度,可以分为很强、强、中等、弱和很弱五种程度。 耦合(coupling)是指程序模块之间的相互依赖程度,或者说是模块之间的联系紧密度,可以分为很强、强、…

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