数据结构 - 散列表,初探

news/2025/3/14 23:56:04/文章来源:https://www.cnblogs.com/hugogoos/p/18506816

今天我们继续学习新的数据结构-散列表。

01、定义

我们先来了解一些常见概念名词解释。

散列:散列表的实现叫做散列,是一种实现以常数级时间复杂度执行查找、插入和删除的技术;

散列值:通过散列函数对输入值(key)计算出来的结果,用来表示key的唯一性,它通常是一个长度固定的值,即无论key多大,散列值的长度都是固定的;

散列地址:通过散列值计算出来的存储位置,即存储value的位置,通常使用散列值和散列表的大小取模得到散列地址。

碰撞:也叫冲突,指两个不同的key,经过散列函数计算后得到相同的散列值;

负载系数:也叫负载因子,用来衡量散列表填充程度,通过散列表已存储的元素个数除以散列表的大小计算可得;

散列函数:也叫哈希函数,指将key映射为散列值的函数;

散列表又称哈希表,是以「key-value」形式存储数据的数据结构。可以理解为任意的key都可以唯一对应到内存中的某个地址,而这个地址就存放着value,通过key快速查找到value。也可以把散列表理解为一种高级的数组,其中key就相当于数组下标,此数组下标不但可以是整数,还可以是浮点数、字符串、结构体等,其中value就相当于数组元素值。

通过前面的数据结构学习,我们知道数组是查找容易、插入和删除困难;链表是查找困难、插入和删除容易;而散列表是集两者之大成,做大查找、插入、删除都容易的一种数据结构。

本质上来说散列表就是一个数组。虽然上面把key比作数组下标,但是key并不真的是数组下标。因此这中间就需要一个转换工具把key转换为数组下标,而这个工具就是散列函数。

如下图,展示了在散列表中如何通用key获取到value的过程。输入key4通过散列函数计算得到数组索引3,最后通过数组下标取出value4。

02、散列函数

散列技术核心难点之一就是如何设计一个准确、快速、均匀、抗碰撞的散列函数。而一个好的散列函数对散列表是至关重要的,这影响散列表的存储和检索效率。

1、四大特性

(1)确定性:指相同的输入key总能输出相同的结果;

(2)快速计算:指计算散列值的速度尽可能的快;

(3)均匀分布:指尽量将输入key均匀的映射到散列表中,以减少碰撞;

(4)抗碰撞性:指尽量减少不同的输入key生成出相同的散列值概率;

2、常见散列函数算法

(1)取模算法

该算法是一种最简单且常用的散列函数构造方法。

原理:通过将key取模散列表的大小(通常是质数)来计算散列值;

公式:hash(key) = key % m;

优点:简单易实现,计算速度快;

缺点:如果m不是质数,会增加碰撞概率,因此m最好选用质数来减少碰撞概率。

示例:假设我们有个散列表,大小为10,分别散列以下key:11,23,4,19

hash(11) = 11 % 10 = 1

hash(23) = 23 % 10 = 3

hash(4) = 4 % 10 = 4

hash(17) = 17 % 10 = 7

则最终生成的散列值分别为1、3、4、7,而这些值就可以作为散列表的索引。

(2)乘法算法

该算法是通过乘法来降低碰撞概率,以使散列值均匀分布;

原理:通过将key与一个固定常数 A(通常是黄金比例的倒数)相乘,取其乘积的小数部分,再乘以散列表的大小(通常是质数),所得结果的整数部分即为散列值;

公式:hash(key) = ⌊m * (key * A % 1)⌋;

优点:简单易实现,散列值分布更均匀;

缺点:常数A的选择对计算结果散列值影响很大,选择不好很容易增加碰撞概率;

示例:假设我们有个散列表,大小为10,常数A为0.618,分别散列以下key:11,23,4,19

hash(11) = ⌊10 * (11 * 0.618 % 1)⌋ = 7

hash(23) = ⌊10 * (23 * 0.618 % 1)⌋ = 2

hash(4) = ⌊10 * (4 * 0.618 % 1)⌋ = 4

hash(17) = ⌊10 * (17 * 0.618 % 1)⌋ = 5

则最终生成的散列值分别为7、2、4、5,而这些值就可以作为散列表的索引。

(3)DJB2算法

DJB2 是一种使用广泛的字符串散列算法,它简单而高效,由 Daniel和J. Bernstein 提出。其核心公式:hash = hash * 33 + c,其中 33 是常用的基数。

原理:使用一个初始散列值(通常是5381),然后通过对key的每一个字符的ASCII值进行逐步加权处理,最终得到散列值;

公式:hash(key) = {

hash = 5381

for character c in string:

hash = ((hash << 5) + hash) + c

return hash & 0xFFFFFFFF

}

优点:简单易懂,速度快,底碰撞;

缺点:基数(33)的选择对散列性能有一定影响,虽然普遍表现良好,但并不是最佳选择;散列值的输出通常需要进行掩码操作(如 & 0xFFFFFFFF),这可能导致部分信息丢失,尤其在处理较大数据时。

上面的公式中没有使用hash * 33 + c,而是使用((hash << 5) + hash) + c是因为位运算效率更高。

(4)其他算法

除了以上三种算法还有很多其他算法,比如和DJB2算法类似的BKDR算法、PJW算法,比如还有诸如:直接定算法、数字分析算法、平方取中算法、折叠算法、随机数算法等等,这里就不一一细说了,有兴趣的可以自己研究研究。

:测试方法代码以及示例源码都已经上传至代码库,有兴趣的可以看看。https://gitee.com/hugogoos/Planner

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/822616.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言中数组的声明喝初始化的区别和联系

声明是不赋值; 初始化是给数组元素赋值。 001、[root@PC1 test]# ls test.c [root@PC1 test]# cat test.c ## 测试c程序 #include <stdio.h>int main(void) {int ay[3]; // 声明,不赋值int by[3] = {3,8,2}; …

Linux虚拟机网络配置

本章将和大家分享VMware虚拟机安装Linux系统时如何进行网络配置。本章将和大家分享VMware虚拟机安装Linux系统时如何进行网络配置。 一、设置 VMware 虚拟网络选择虚拟网络编辑器:选择更改设置:此处选择VMnet0、桥接模式、自动,然后应用并确定。 二、编辑 Linux 虚拟机网络点…

Golang Agent 可观测性的全面升级与新特性介绍

自 2024 年 6 月 26 日,ARMS 发布了针对 Golang 应用的可观测性监控功能以来,阿里云 ARMS 团队与程序语言与编译器团队一直致力于不断优化和提升该系统的各项功能,旨在为开发者提供更加全面和深入的应用性能监控体验。作者:张海彬(古琦) 背景 自 2024 年 6 月 26 日,ARM…

2024-2025-1 20241322《计算机基础与程序设计》第5周学习总结

2024-2025-1 20241322《计算机基础与程序设计》第5周学习总结 作业信息这个作业属于哪个课程 https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP这个作业要求在哪里 https://www.cnblogs.com/rocedu/p/9577842.html#WEEK05这个作业的目标 <Pep/9虚拟机 机器语言与汇编…

【CodeForces训练记录】Codeforces Round 982 (Div. 2)

训练情况赛后反思 A题3分钟秒了,神必B题,剩下两个小时罚坐,超! A题 我们容易发现,这一坨东西的周长等效于它变成长方形的周长,就把每一条边移出来。因为长宽更大的情况下,无论如何横竖放都会对答案有贡献,所以我们放的时候尽可能长宽重复覆盖,最后取长和宽的最大值,所…

2024-2025 20241318《计算机基础与程序设计》第五周学习总结

这个作业属于哪个课程 <班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>(如2024-2025-1计算机基础与程序设计第五周作业)这个作业的目标 计算机科学概论(第七版)第6章 并完成云班课测试《C语言程序设计》第4章并完成云班…

2024-2025-1 20241305 《计算机基础与程序设计》第五周学习总结

作业信息这个作业属于哪个课程 2024-2025-1-计算机基础与程序设计(https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP))这个作业要求在哪里 2024-2025-1计算机基础与程序设计第五周作业(https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP/homework/13276))这个作业…

阿里云开源 AI 应用开发框架:Spring AI Alibaba

Spring AI Alibaba 项目的产生背景是生成式 AI 与大模型在过去一年的快速发展,大家应该有直观的感受,周边所有人都在聊模型服务,但是训练大模型本身是少部分企业和算法工程师的职责,我们作为使用方、开发者,更关注的应该是如何为我们的应用接入生成式AI能力。作者:刘军,…

c++程序设计基础实验2

任务1: 测试代码: task1.cpp#pragma once #include <string> // 类T: 声明 class T { // 对象属性、方法 public: T(int x = 0, int y = 0); // 普通构造函数 T(const T &t); // 复制构造函数 T(T &&t); // 移动构造函数 ~T(); // 析构函数 t.cpp void adj…

JAVA第一次博客作业

一、前言总结三次题目集的知识点、题量、难度等情况这三次题目集的最后一道大作业是一系列递进的编程作业。 第一次作业 答题判题程序-1  设计一个简单的答题判题程序,要求输入题目信息和答题信息,根据标准答案判断答题结果。 主要知识点: 基本的类设计和对象创建。输入输…

如何阅读 CPU 电路图(以 6502 为例)

开篇 你是否曾对 CPU 的工作原理充满好奇,以及简单的晶体管又是如何组成逻辑门,进而构建出复杂的逻辑电路实现?本文将以知名的 6502 CPU 的电路图为例,介绍如何阅读 CPU 电路图,并向你演示如何从晶体管电路还原出逻辑门电路。通过这篇文章的引导,你将能够揭开 CPU 复杂设…

RSA公钥文件解密密文

RSA公钥文件解密密文RSA公钥文件解密密文 做题遇到两个从未见过的文件:flag.enc …