数据结构与算法学习-哈希表入门

初学算法(一):哈希算法 一、什么是哈希 哈希算法又称散列函数算法,本质是一种查找算法。简单来讲就是将数据按照一种规定好的方法进行映射,映射成更加易于查找的方式。但是这种映射关系有可能会发生多个数据映射到同一个地址的现象,我们称为哈希冲突。在这种情况下,我们进行二次或者多次处理。 1、常见的数据查找算法 (1)顺序查找:最简单的查找方式,将数据集中的每一个数据逐个进行匹配,效率极低,无法进行大数据量查找。 (2)二分法查找... 阅读详情

哈希表:又叫散列表,关键值通过哈希函数生成一个哈希地址映射到数组对应的存储位置上,查找时通过关键值直接访问数组。就好比把一个复杂的事务通过一种方式简化成一个小物件,这个小物件就代表了这个复杂的事物。

哈希函数:指的是关键值和存储位置建立的对应关系。

一般我们只需要一次查找就能找到目标位置,但有些关键字需要多次比较和查找才能找到。因为哈希表里,可能存在关键值不同但是由于哈希函数的计算方式导致生成的哈希地址相同的情况,产生了冲突,一般情况下,冲突是不可避免的,因为关键字集合往往比哈希地址集合大很多。

由此可见,选择合适的哈希函数就显得特别的重要,要尽可能的避免冲突。

哈希函数常见的构造方法:

1.    直接寻址法:即取关键值或关键字的某个函数变换值,直接映射到存储地址上(适用于关键字的数量和跨度不大),优点在于简单有效,避免了冲突。

2.    除留余数法:关键字对整数p取模直接作为存储地址。

3.    其它:分析数字法、随机数法。

总之,哈希函数并没有统一的方法,同一个哈希函数不一定适用于所有问题。一般有2个要求:计算简单,过于复杂的哈希函数会增加时间的开销;关键字尽可能均匀分到存储地址上,这样可减少冲突。

当冲突不可避免的时候,我们就需要考虑怎么处理冲突。

常见处理冲突的方法:

一.开放地址法(仍用数组):

       如果发生冲突,那么就使用某种策略寻找下一存储地址,直到找到一个不冲突的地址或者找到关键字,否则一直按这种策略继续寻找。如果冲突次数达到了上限则终止程序,表示关键字不存在哈希表里。一般常见的策略有这几种:

1.    线性探测法,如果当前的冲突位置为d,那么接下来几个探测地址为d+1,d+2,d+3等,也就是从冲突地址往后一个一个的检测,遍历整个数组;

2.    线性补偿探测法,它形成的探测地址为d+m,d+2*m,d+3*m等,与线性探测法不同,这里的查找单位不是1,而是m,为了能遍历到哈希表里面所有位置,我们设置m和表长size互质。

3.    随机探测法,这种方法和前两种方法类似,这里的查找单位不是一个固定值,而是一个随机序列。

4.    二次探测法,它形成的探测地址为d+1^2,d-1^2,d+2^2,d-2^2等,这种方法在冲突位置左右跳跃着寻找探测地址。

开放地址法计算简单快捷,处理起来方便,但是也存在不少缺点。线性探测法容易形成”堆聚”的情况,即很多记录就连在一块,而且一旦形成堆聚,记录会越聚越多。另外,开放地址法都有一个缺点,删除操作显得十分复杂,我们不能直接删除关键字所在的记录,否则在查找删除位置后面的元素时,可能会出现找不到的情况,因为删除位置上已经成了空地址,查找到这里时会终止。

二.链地址法(使用链表)

       该方法将所有哈希地址相同的节点构成一个单链表,单链表的头节点存在哈希数组里。链地址法常出现在经常插入和删除的情况下。

       链地址法有以下优点:1.不会出现聚堆现象,哈希地址不同的关键字不会发生冲突;2.不需要重建哈希表,在开放地址法中,如果哈希表里存满关键字了就需要扩充哈希表然后重建哈希表,而在链地址法里,因为结点都是动态申请的,所以不会出现哈希表里存满关键字的情况;相比开放地址法,关键字删除更方便,只需要找到指定节点,删除该节点即可。

总结:开放地址法和链地址法各有千秋,适用于不同的情况。当关键字规模少的时候,开放地址法比链地址法更节省空间,因为用链地址法可能会存在哈希数组出现大量空地址的情况,而在关键字规模大的情况下,链地址法就比开放地址法更节省空间,链表产生的指针域可以忽略不计,关键字多,哈希数组里面产生的空地址就少了。

下面代码采用线性探测法处理冲突:

#include <iostream>
#include <string>
using namespace std;
class HashTable {
private:
    string *elem;
    int size;
public:
    HashTable() {
        size = 2000;  //初始化设置哈希表的大小为2000
        elem = new string[size];
        for (int i = 0; i < size; i++) {  //初始化为#
            elem[i] = "#";
        }
    }
    ~HashTable() {
        delete[] elem;
    }
    int hash(string &index) {   //构造哈希函数
        int code = 0;
        for (size_t i = 0; i < index.length(); i++) {
            code = (code * 256 + index[i] + 128) % size;
        }
        return code;
    }
    bool search(string &index, int &pos, int &times) {  //查找哈希表中是否存在即将插入的关键值
        pos = hash(index);  //生成哈希地址
        times = 0;  //冲突次数初始化为0
        while (elem[pos] != "#" && elem[pos] != index) {  //找到可用的地址
            times++;
            if (times < size) {
                pos = (pos + 1) % size;
            } else {
                return false;
            }
        }
        if (elem[pos] == index) {   //如果该关键值已经存在
            return true;
        } else {
            return false;
        }
    }
    int insert(string &index) {  //插入关键值
        int pos, times;
        if (search(index, pos, times)) {
            return 2;  //存在返回2
        } else if (times < size / 2) {  
            elem[pos] = index;  //插入成功
            return 1;
        } else {   //如果冲突次数大于哈希表的一半,证明产生了聚堆现象,重建哈希表
            recreate();
            return 0;
        }
    }
    void recreate()
    {
        string *temp_elem; //存到临时空间
        temp_elem = new string[size];
        for(int i = 0; i < size; i++)
        {
            temp_elem[i] = elem[i];
        }
        int copy_size = size;
        size *=2;
	delete []elem;
        elem = new string[size]; //扩大一倍的内存
        for(int i = 0; i < size; i++)
        {
            elem[i] = "#";
        }
        for(int i = 0; i < copy_size; i++)
        {
            if(temp_elem[i] != "#")
            {
                insert(temp_elem[i]);
            }
        }
        delete []temp_elem;
    }
};
int main() {
    HashTable hashtable;
    string buffer;
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> buffer;
        int ans = hashtable.insert(buffer);
        if (ans == 0) {
            cout << "insert failed!" << endl;
        } else if (ans == 1) {
            cout << "insert success!" << endl;
        } else if (ans == 2) {
            cout << "It already exists!" << endl;
        }
    }
    int temp_pos, temp_times;
    cin >> buffer;
    if (hashtable.search(buffer, temp_pos, temp_times)) {
        cout << "search success!" << endl;
    } else {
        cout << "search failed!" << endl;
    }
    return 0;
}



数据结构与算法(Python语言实现)算法题目(总集篇) 集合了我学习算法的所有题目,都已经分类归档好! 阅读详情

相关推荐

哈希表算法(闭散列表操作,开散列表操作)创建,查找,插入,删除

#include <stdio.h> #include <malloc.h> #include "stdlib.h" #include <math.h> typedef int Status; typedef int KEYTYPE; typedef struct { KEYTYPE key; }ElemType; typedef struct { ...

qq_45150239的博客 2696

哈希表基础入门

索引 哈希表的概念 哈希函数的构造方法 处理冲突的方法 哈希表的实现 哈希表的查找性能 4.1、哈希表的概念 把关键字集合*K*到一个有限的连续的地址集(区间)D的映射关系表示为: K为主关键字集合,H称为哈希函数或散列函数。按哈希函数构建的表称为哈希表。D的大小m称为哈希表的地址区间长度。 先看一个简单的例子: 假设要建立一个地址区间长度为13的哈希表,哈希函数为 其中函数Ord为求字母再在字母表中的序号。例如,字母A在字母表中的序号为Ord(‘A’)=1。现将关键字依次为Zhao、Qian、Sun

Nulidebaibai的博客 5739

学习数据结构和算法:哈希表的思想与叉树入门

通过示例代码和简单的说明,读者可以初步了解哈希表和叉树的基本思想和实现方式。常用的解决哈希冲突的方法有链地址法和开放寻址法,读者可以进一步了解这些方法的原理和实现。本文将介绍哈希表的思想和叉树,并提供相应的源代码示例,帮助读者理解和应用这些概念。哈希表是一种基于哈希函数的数据结构,用于实现键值对的存储和查找。叉树(Binary Tree)是一种常见的树状数据结构,它由节点和边组成,每个节点最多有两个子节点。叉树的遍历是一种常见的操作,常用的遍历方法有前序遍历、中序遍历和后序遍历。的类,表示叉树的节点。

CyberSparkZ的博客 82

一文带你快速入门【哈希表】

超详细讲解数据结构 ——哈希表,配有内存原理图和架构图,带你快速入门哈希表!!!

做技术人 · 产优质博客 · 找好工作 1194

1、数据结构与算法入门指南

本博客为《数据结构与算法入门指南》,旨在帮助计算机科学及相关专业的学生深入了解数据结构与算法的核心概念、实现方式及其实际应用。内容涵盖基础理论、常见数据结构(如链表、二叉搜索树、堆)、算法分析(时间复杂度、空间复杂度)以及优化方法,并结合示例代码和实践建议,提升读者的编程能力和问题解决能力。

vvv99的博客 92

哈希表Hash的学习,非常适合初学者和后续的深入开发

非常适合初学者进行学习哈希表,进行哈希表的练习操作,对哈希表和其它查找方法进行了比较,对哈希函数构造的方法也给出了实例。

构造哈希表的几种算法

1、直接定址法 例如:有一个从1到100岁的人口数字统计表,其中,年龄作为关键字,哈希函数取关键字自身。 但这种方法效率不高,时间复杂度是O(1),空间复杂度是O(n),n是关键字的个数 2、数字分析法 有学生的生日数据如下: 年.月.日 75.10.03   75.11.23   76.03.02   76.07.12   75.04.21   76.02.15   … 经分析,第一位,第二位,...

qq_42449963的博客 2173

UnicodeEncodeError: ‘ascii‘ codec can‘t encode characters in position 0-4: ordinal not in range(128)

python3报错处理:UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-4: ordinal not in range(128) 一、报错场景 // 报错代码 Traceback (most recent call last): File "test_autoo3_2.py", line 214, in <module> main() File "test_autoo3_2.py",

浪里小飞侠的博客 4201

【数据结构】哈希表(也称散列表)——入门这一篇就够了!

在讲散列表之前,我们先回顾总结下两种最基本数据结构——数组和链表的基本特点。 数组:寻址容易,插入和删除元素困难; 链表:寻址困难,插入和删除元素容易。 数组 链表 读取 O(1) 插入 删除 ...

weixin_46318945的博客 1405

海康VisionMaster表面缺陷滤波实战:从参数调优到工业检测避坑指南

本文深入探讨海康VisionMaster表面缺陷滤波技术在工业检测中的应用,从参数调优到ROI绘制与Blob分析的协同策略,提供金属外壳、锂电池铝壳等复杂表面的缺陷检测实战指南。通过多级滤波架构和动态ROI生成法,显著提升检出率至98.7%,误检率低于0.5%,为工业质检提供智能化解决方案。

ujm5678901的博客 328

逆变器并联--下垂控制引入虚拟阻抗

说明传统下垂控制的缺点、分析虚拟阻抗的原理和实现方法

weixin_58670090的博客 1万+

数据结构学习入门

数据结构(Data Structure)是计算机存储、组织数据的方式。它提供了一种高效的方式来管理和操作数据。数据结构不仅影响程序的执行效率,也决定了数据的存储方式和访问方法。数据结构的选择直接影响算法的性能。一个好的数据结构能够提高程序的运行速度并减少存储空间的占用,因此,学习数据结构是计算机科学领域的重要基础。学习数据结构是编程和算法的基础,不同的数据结构适用于不同的应用场景。希望这篇文章能帮助你理解数据结构的基本概念和实现方法!

百锦再的博客 3585

GNSS数据资源全解析:从DCB到BSX文件的下载与应用指南

本文系统解析了GNSS数据处理所需的核心数据资源,包括DCB、BSX、SP3、CLK等关键文件的官方下载路径与应用方法。详细介绍了CDDIS、武汉大学镜像站等权威数据源,并提供了从数据下载到实际应用的完整指南,帮助用户高效获取GNSS数据,提升精密定位处理效率。

weixin_29246195的博客 140

恶补数据结构与算法

突然发现要打算长远从事开发这一岗位,短期可能code技巧重要,但长期发展需要更底层算法角度进行发展。不幸的是我这块知识点很薄弱,不过,学习何时也不算晚嘛!

qq_43154503的博客 390

OpenHarmony + AI:深度解析 Whisper.cpp 智慧语音系统级移植与 NAPI 封装实战

【代码】OpenHarmony + AI:深度解析 Whisper.cpp 智慧语音系统级移植与 NAPI 封装实战。

m0_67505153的博客 188

《算法图解》让我们一起边读小说边入门算法

本书运用的大量的图片示例,推荐没有了解过算法的小白去阅读,真的是对新手相当友好了,唯一可惜的地方在于书中的代码实现是用的python2.7。

weixin_45797022的博客 1076

uniapp 全局弹窗

功能详解1.有的组件需要全局调用,不想要在一个页面里面一个个引入,现在就需要写入到全局中,直接全局触发。2.通过 $rechargePop就能全局触发 充值的弹窗实现步骤一、先把组件封装好,如 rechargePop组件位置 components/RechargePop/index.vue ,就定义一个methods open方法就可以 二、在同级别路径下定义一个 index.js 三、引入到main.js 四、全局调用this.$rechargePop(); 就能弹出那个弹窗

weixin_42066070的博客 657

「 数据结构与算法 」如何系统性的学习数据结构与算法

更多、更体系化的内容请持续关注专栏,您的都将是小编持续创作的动力!(1)入门(2)基础(3)进阶、高级(4)实战想要学习数据结构与算法,最重要的概念是—复杂度分析,必须熟练拿下,否则数据结构与算法等于没学;排序查找正则表达式数据压缩块动态查找表二叉查找树。

大白吃饱了吗的技术博客 415

一篇把 Transport 做到可复制的实战指南:从 CTS 底层表到 LSMW、Variant、Layout、TABU、Query、SAPscript 全对象搬运

本文深入解析SAP系统中的Transport机制,将其视为可审计、可追溯的变更流水线。文章从CTS/Transport Organizer通用方法论和具体对象搬运手法两个层面展开,详细介绍了LSMW项目、程序Variant、屏幕/ALV Layout、表数据、ABAP Query、SAPscript和SO10标准文本等对象的传输策略。通过真实案例说明,代码对象往往能被正确传输,但"运行体验"和"业务配置"却常被遗漏,导致QAS测试正常而PRD环境异常。文章提供了一套可

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 171

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Hello 算法:动画图解数据结构与算法入门教程

《Hello 算法》是一本通过动画图解和可运行代码讲解数据结构与算法的开源入门教程,GitHub获128K星。内容涵盖数组、链表、排序等基础知识点,以动态演示降低理解门槛,支持12种编程语言实现,适合计算机学生、面试者及自学者。提供在线阅读和PDF版本,项目由社区共同维护,保持内容精简实用,避免过度深入。其直观的教学方式和多语言支持使其成为算法初学者的友好选择。

sigmaloft284的博客 700

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

数据结构与算法学习笔记----哈希表

@ author: 明月清了个风。

weixin_60278491的博客 2368

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

07 数据结构和算法——散列表(哈希表)

散列表:(Hash Table,又称为哈希表),是一种线性表的存储结构,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。哈希表由一个直接寻址表和一个哈希函数组成。哈希函数h(k)将k作为自变量,返回元素的存储下标。 哈希表在应用中也是比较常见的,就如Java中有些集合类就是借鉴了哈希原理构造的,例...

数据知道的博客 3万+

【算法】哈希表

本次为大家带来的是哈希表在算法中的应用与实践,主要讲解哈希表的思路以及在算法题中的应用,本篇文章由于是面向算法党的,对于工程实现部分讲解较为粗糙,以后会在STL中详细讲解工程实现。当然,本篇文章会给出哈希表的两种快速实现,希望大家能将这两个模板理解记忆,方便面试中或者算法竞赛中快速实现。散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。

白晨的博客 3347

『数据结构与算法』散列表(哈希表)

GitHub源码分享 微信搜索:码农StayUp 主页地址:https://gozhuyinglong.github.io 源码分享:https://github.com/gozhuyinglong/blog-demos 1. 什么是散列表 散列表(Hash Table)也叫哈希表,是根据给定关键字(Key)来计算出该关键字在表中存储地址的数据结构。也就是说,散列表建立了关键字与存储地址之间的一种直接映射关系,将关键字映射到表中记录的地址,这加快了查找速度。 使用函数表达式来表示,应为:hash(ke.

人生就是一个不断学习的过程 2700

【学点数据结构和算法】04-散列表

写在前面: 博主是一名大数据的初学者,昵称来源于《爱丽丝梦游仙境》中的Alice和自己的昵称。作为一名互联网小白,写博客一方面是为了记录自己的学习历程,一方面是希望能够帮助到很多和自己一样处于起步阶段的萌新。由于水平有限,博客中难免会有一些错误,有纰漏之处恳请各位大佬不吝赐教!个人小站:http://alices.ibilibili.xyz/ , 博客主页:https://alice.blog.youkuaiyun.com/ 尽管当前水平可能不及各位大佬,但我还是希望自己能够做得更好,因为一天的生活就是一生的缩影。.

大数据梦想家 6094
上一篇: 排序算法-直接插入排序
下一篇: 数据结构与算法学习-二叉树
UKey_
博客等级 码龄10年 258粉丝 186原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值