当前位置: 首页 > article >正文

哈希(C语言)

文章目录

  • 1.数据结构——哈希表
    • 1.1哈希表的工作原理
    • 1.2哈希表的代码实现
  • 2.哈希算法
    • 2.1 哈希算法介绍
    • 2.2C语言实现示例

本文介绍一个常用的算法——哈希算法,哈希算法依赖于哈希表来实现,首先我会介绍一下哈希表,并在哈希表的基础上衍生出哈希算法。

1.数据结构——哈希表

哈希表(hash table),又称散列表,它通过建立键key 与值value 之间的映射,实现高效的元素查询。具体而言,我们向哈希表中输入一个键key ,则可以在𝑂(1) 时间内获取对应的值value 。
除哈希表外,数组和链表也可以实现查询功能,它们的效率对比如表所示。

  • 添加元素:仅需将元素添加至数组(链表)的尾部即可,使用𝑂(1) 时间。
  • 查询元素:由于数组(链表)是乱序的,因此需要遍历其中的所有元素,使用𝑂(𝑛) 时间。
  • 删除元素:需要先查询到元素,再从数组(链表)中删除,使用𝑂(𝑛) 时间。
数组链表哈希表
查找元素O(n)O(n)O(1)
添加元素O(1)O(1)O(1)
删除元素O(n)O(1)O(1)
观察发现,在哈希表中进行增删查改的时间复杂度都是𝑂(1) ,非常高效。

1.1哈希表的工作原理

我们先考虑最简单的情况,仅用一个数组来实现哈希表。在哈希表中,我们将数组中的每个空位称为桶(bucket),每个桶可存储一个键值对。因此,查询操作就是找到key 对应的桶,并在桶中获取value 。那么,如何基于key 定位对应的桶呢?这是通过哈希函数(hash function)实现的。哈希函数的作用是将一个较大的输入空间映射到一个较小的输出空间。在哈希表中,输入空间是所有key ,输出空间是所有桶(数组索引)。换句话说,输入一个key ,我们可以通过哈希函数得到该key 对应的键值对在数组中的存储位置。
输入一个key ,哈希函数的计算过程分为以下两步。

  1. 通过某种哈希算法hash() 计算得到哈希值。
  2. 将哈希值对桶数量(数组长度)capacity 取模,从而获取该key 对应的数组索引index 。

1.2哈希表的代码实现

typedef struct {  
    int key;  
    char *val;  
} Pair;  
/* 基于数组实现的哈希表*/  
typedef struct {  
    Pair *buckets[MAX_SIZE];  
} ArrayHashMap;  
/* 构造函数*/  
ArrayHashMap *newArrayHashMap() {  
    ArrayHashMap *hmap = malloc(sizeof(ArrayHashMap));  
    for (int i=0; i < MAX_SIZE; i++) {  
        hmap->buckets[i] = NULL;  
    }  
    return hmap;  
}  
/* 析构函数*/  
void delArrayHashMap(ArrayHashMap *hmap) {  
    for (int i = 0; i < MAX_SIZE; i++) {  
        if (hmap->buckets[i] != NULL) {  
            free(hmap->buckets[i]->val);  
            free(hmap->buckets[i]);  
        }  
    }  
    free(hmap);  
}  
/* 添加操作*/  
void put(ArrayHashMap *hmap, const int key, const char *val) {  
    Pair *Pair = malloc(sizeof(Pair));  
    Pair->key = key;  
    Pair->val = malloc(strlen(val) + 1);  
    strcpy(Pair->val, val);  
    int index = hashFunc(key);  
    hmap->buckets[index] = Pair;  
}  
/* 删除操作*/  
void removeItem(ArrayHashMap *hmap, const int key) {  
    int index = hashFunc(key);  
    free(hmap->buckets[index]->val);  
    free(hmap->buckets[index]);  
    hmap->buckets[index] = NULL;  
}  
/* 获取所有键值对*/  
void pairSet(ArrayHashMap *hmap, MapSet *set) {  
    Pair *entries;  
    int i = 0, index = 0;  
    int total = 0;  
    /* 统计有效键值对数量*/  
    for (i = 0; i < MAX_SIZE; i++) {  
        if (hmap->buckets[i] != NULL) {  
            total++;  
        }  
    }  
    entries = malloc(sizeof(Pair) * total);  
    for (i = 0; i < MAX_SIZE; i++) {  
        if (hmap->buckets[i] != NULL) {  
            entries[index].key = hmap->buckets[i]->key;  
            entries[index].val = malloc(strlen(hmap->buckets[i]->val) + 1);  
            strcpy(entries[index].val, hmap->buckets[i]->val);  
            index++;  
        }  
    }  
    set->set = entries;  
    set->len = total;  
}  
/* 获取所有键*/  
void keySet(ArrayHashMap *hmap, MapSet *set) {  
    int *keys;  
    int i = 0, index = 0;  
    int total = 0;  
    /* 统计有效键值对数量*/  
    for (i = 0; i < MAX_SIZE; i++) {  
        if (hmap->buckets[i] != NULL) {  
            total++;  
        }  
    }  
    keys = malloc(total * sizeof(int));  
    for (i = 0; i < MAX_SIZE; i++) {  
        if (hmap->buckets[i] != NULL) {  
            keys[index] = hmap->buckets[i]->key;  
            index++;  
        }  
    }  
    set->set = keys;  
    set->len = total;  
}  
/* 获取所有值*/  
void valueSet(ArrayHashMap *hmap, MapSet *set) {  
    char **vals;  
    int i = 0, index = 0;  
    int total = 0;  
    /* 统计有效键值对数量*/  
    for (i = 0; i < MAX_SIZE; i++) {  
        if (hmap->buckets[i] != NULL) {  
            total++;  
        }  
    }  
    vals = malloc(total * sizeof(char *));  
    for (i = 0; i < MAX_SIZE; i++) {  
        if (hmap->buckets[i] != NULL) {  
            vals[index] = hmap->buckets[i]->val;  
            index++;  
        }  
    }  
    set->set = vals;  
    set->len = total;  
}  
/* 打印哈希表*/  
void print(ArrayHashMap *hmap) {  
    int i;  
    MapSet set;  
    pairSet(hmap, &set);  
    Pair *entries = (Pair *)set.set;  
    for (i = 0; i < set.len; i++) {  
        printf("%d -> %s\n", entries[i].key, entries[i].val);  
    }  
    free(set.set);  
}

2.哈希算法

2.1 哈希算法介绍

哈希算法是一种将任意长度的数据转换为固定长度的输出的算法。这种输出通常被称为哈希值或消息摘要。哈希算法具有以下特性:

  • 确定性:相同的输入总是产生相同的输出。
  • 快速计算:计算哈希值的速度通常很快。
  • 雪崩效应:输入的微小变化会导致输出的显著变化。
  • 抗碰撞性:找到两个不同的输入产生相同输出的情况非常困难。

常见的哈希算法

  • MD5
  • SHA-1
  • SHA-256
  • SHA-3

2.2C语言实现示例

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

#define HASH_TABLE_SIZE 256

// 一个简单的哈希函数
unsigned int simple_hash(const unsigned char *str) {
    unsigned int hash = 0;
    for (int i = 0; str[i] != '\0'; i++) {
        hash += str[i]; // 这里使用了字符的ASCII值
    }
    return hash % HASH_TABLE_SIZE; // 取模运算以适应哈希表大小
}

int main() {
    const char *input = "Hello, World!";
    unsigned int hash_value = simple_hash((const unsigned char *)input);
    printf("The hash value of '%s' is: %u\n", input, hash_value);
    return 0;
}

http://www.kler.cn/a/283850.html

相关文章:

  • 浅谈:基于三维场景的视频融合方法
  • kafka面试题解答(四)
  • OCR识别铁路电子客票
  • MoneyPrinterTurbo – 开源的AI短视频生成工具
  • CSS多列布局:打破传统布局的束缚
  • 封装el-menu
  • 华为设备ENSP-AAA认证配置
  • Python | Leetcode Python题解之第386题字典序排数
  • FPGA 学习之路:挑战与策略
  • 磁盘I/O性能优化示例
  • Go 语言中的接口详解
  • Django 使用Apscheduler执行定时任务
  • vue nginx部署 配置 解决href = ‘/login路由‘ 跳转404问题
  • 代码随想录刷题day17丨654.最大二叉树,617.合并二叉树,700.二叉搜索树中的搜索,98.验证二叉搜索树
  • Java线程生命周期详解_(1)
  • 在 Maven 的 POM 文件中配置 npm 镜像源
  • SpringMVC处理流程介绍
  • 【HuggingFace Transformers】BertSelfOutput 和 BertOutput源码解析
  • 开源个人云存储管理专家:Cloudreve
  • 零基础入门转录组数据分析——单基因ROC分析
  • Leetcode Java学习记录——动态规划基础_3
  • 尚硅谷大数据技术-Kafka视频教程-笔记01【Kafka 入门】
  • 8月30复盘日记
  • k8s-pod 实战四 什么是 Kubernetes Pod?如何在生产环境中使用它?(学习专场,实战就看这一篇就够了)
  • 把http网站变成https
  • WPF 使用PdfiumViewer实现PDF预览与打印