哈希(C语言)
本文介绍一个常用的算法——哈希算法,哈希算法依赖于哈希表来实现,首先我会介绍一下哈希表,并在哈希表的基础上衍生出哈希算法。
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 ,哈希函数的计算过程分为以下两步。
- 通过某种哈希算法hash() 计算得到哈希值。
- 将哈希值对桶数量(数组长度)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;
}
哈希(C语言)的更多相关文章
- [转] JavaScript中的属性:如何遍历属性
在JavaScript中,遍历一个对象的属性往往没有在其他语言中遍历一个哈希(有些语言称为字典)的键那么简单.这主要有两个方面的原因:一个是,JavaScript中的对象通常都处在某个原型链中,它会从 ...
- 【转载】JavaScript中的属性:如何遍历属性
转载自:http://www.cnblogs.com/ziyunfei/archive/2012/11/03/2752905.html 在JavaScript中,遍历一个对象的属性往往没有在其他语言中 ...
- 简单的哈希表实现 C语言
简单的哈希表实现 简单的哈希表实现 原理 哈希表和节点数据结构的定义 初始化和释放哈希表 哈希散列算法 辅助函数strDup 哈希表的插入和修改 哈希表中查找 哈希表元素的移除 哈希表打印 测试一下 ...
- Swift3.0语言教程获取字符串编码与哈希地址
Swift3.0语言教程获取字符串编码与哈希地址 Swift3.0语言教程获取字符串编码与哈希地址,以下将讲解字符串中其它内容的获取方法. 1.获取字符串编码 在NSString中可以使用2个属性获取 ...
- C语言-简单哈希表(hash table)
腾讯三面的时候,叫我写了个哈希表,当时紧张没写好···结果跪了··· 回来后粪发涂墙,赶紧写了一个! 什么都不说了···先让我到厕所里面哭一会··· %>_<% 果然现场发挥,以及基础扎实 ...
- R语言实现︱局部敏感哈希算法(LSH)解决文本机械相似性的问题(二,textreuse介绍)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 上一篇(R语言实现︱局部敏感哈希算法(LSH) ...
- BZOJ_1212_[HNOI2004]L语言_哈希
BZOJ_1212_[HNOI2004]L语言_哈希 Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写 ...
- 一致性哈希算法和Go语言实现
一致性哈希算法,当我第一次听到这个名字的时候,感觉特别高深.而它往往会和分布式系统相关,准确的说,是分布式缓存. 在Web服务中,缓存是介于数据库和服务端程序之间的一个东西.在网站的业务还不是很大的时 ...
- 哈希表(散列表)—Hash表解决地址冲突 C语言实现
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.具体的介绍网上有很详 ...
- 【转载】网络攻击技术(三)——Denial Of Service & 哈希相关 & PHP语言 & Java语言
找到了这个系列的原始作者: http://www.cnblogs.com/rush/archive/2012/02/05/2339037.html 最近网络安全成了一个焦点,除了国内明文密码的安全事件 ...
随机推荐
- Docker不同宿主机网络打通
本方式使用docker Swarm集群的方式创建overlay 网络进行打通 背景 因java微服务使用nacos做配置中心,为了解决Nacos服务注册使用Docker容器内网ip问题,使用此方案 前 ...
- Redis分布式锁防止缓存击穿
一.Nuget引入 StackExchange.Redis.DistributedLock.Redis依赖 二.使用 StackExchange.Redis 对redis操作做简单封装 public ...
- Webpack 核心流程
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:霜序 三个阶段 初始化阶段 初始化参数:从配置文件.配置对 ...
- One-for-All:上交大提出视觉推理的符号化与逻辑推理分离的新范式 | ECCV 2024
通过对多样化基准的严格评估,论文展示了现有特定方法在实现跨领域推理以及其偏向于数据偏差拟合方面的缺陷.从两阶段的视角重新审视视觉推理:(1)符号化和(2)基于符号或其表示的逻辑推理,发现推理阶段比符号 ...
- 【爬虫实战】——利用bs4和sqlalchemy操作mysql数据库,实现网站多行数据表格爬取数据
前言 此篇接上一篇的内容,在其基础上爬取网站的多行表格数据,以及把数据写入到mysql数据库中 目录 一.定位表格查找元素 二.提取数据 三.写入mysql数据库 四.附录 一.定位表格查找元素 首先 ...
- Feign 动态设定服务器名称 与 调用接口
1. 新增编码器(由于使用了动态的Feign,所以不能像正常使用Feign一样指定configuration配置编码器) import feign.RequestTemplate; import fe ...
- SpringMVC初体验
目录 SpringMVC简介 MVC介绍 什么是SpringMVC SpringMVC的特点 入门案例 创建maven工程 配置web.xml 默认配置方式 扩展配置方式 url-pattern标签中 ...
- 熔断、限流、降级 —— SpringCloud Hystrix
概述 Hystrix 为 微服务架构提供了一整套服务隔离.服务熔断和服务降级的解决方案.它是熔断器的一种实现,主要用于解决微服务架构的高可用及服务雪崩等问题 Hystrix 的特性如下: 服务熔断:H ...
- if else 代码优化实战
前言 介绍几种方法,不使用if else语句也能做条件判断. 一:使用枚举 首先定义一个公用接口 RoleOperation,表示不同角色所能做的操作 package com.gavin.enums; ...
- Angular 18+ 高级教程 – Component 组件 の Template Binding Syntax
前言 这篇介绍一些基本的 Angular 模板语法. 参考 Docs – Understanding binding Render.Event Listening and DOM Manipulati ...