算法与数据结构 - 散列表

news2025/7/18 7:57:05

文章目录

  • 引言
  • 一、散列表概述
    • 1.1 哈希函数
    • 1.2 散列表
  • 二、算法实战
    • 2.1 两数之和
      • 题目
      • 题解
        • 1. 暴力破解
        • 2. hash表
  • 结语

点赞再看,养成习惯


引言

某日,韩梅梅和李雷来到一家新开的网红图书馆借阅书籍。
韩梅梅: 李雷,快来帮我找下《数据结构从入门到放弃》
李雷看了下周围书籍拜访,一脸苦恼的说: 这家图书馆的书籍摆放并不是很科学,可能我们要费一些时间~
韩梅梅:为什么不科学呢?
李雷:因为它摆放 书籍并没有按照某种规律进行拜访,我们查找书籍就只能够随机的去寻找,这样无疑是很浪费时间的。
韩梅梅:那你有办法优化下吗?
李雷:当然!

一、散列表概述

我们先不管什么是哈希表,先来看下如果物品没有规律随即摆放会怎么样。比如此时我们有Java,C,C++,C#,Python,JS,Mysql,Go,Rust几本书,如果我们随即摆放并查找Rust,可能出现的最坏情况如下:
在这里插入图片描述
由于没有规律,我们只能够进行按照已有顺序进行随机访问,经过9次才找到我们的目标书籍。但如果我们按照书籍的首字母进行归纳,然后再进行查找,最坏情况又会不同:
在这里插入图片描述
我们仅需6次就可以完成之前需要9次查找就可以完成的工作。当然这时候会有小伙伴有疑问,如果我所有书籍首字母都不同怎么办?我们显然不能够所有场景都按照字典目录的方式进行归纳,这种时候就需要我们提出一种新的方法来解决数据归纳的问题。

1.1 哈希函数

什么是哈希函数? 我们可以简单的将它理解为是一种接口转换器。我们将已有的数据经过哈希函数加工后会得到一种固定长度的无规律数值,转换出来的数值就可以用在各种各样的场景中。

这里要简单的说一下,哈希函数有很多种算法实现,比如我们在密码安全加密方面常见的MD5,SHA-1,SHA-2等等,其中SHA-2是我们使用场景最广泛的一种。

哈希函数也是我们使用散列表的必须前提之一,我们需要通过哈希函数来计算元素将要进入我们已经划分好的具体哪个区域。既然如此,我们可以先简单的设计一个哈希算法。

  1. 首先第一步,我们先确定我们会有n个空间用来存放相同函数值的元素
  2. 第二步我们需要确认我们通过什么特征来进行哈希运算,这里我们决定选用字符串的字典序进行。
  3. 最后我们只需要设定规则,我们哈希运算的规则就是字典序 % n 获取到的余数即为哈希结果。

让我们简单的写一段代码:

    public Integer getHashCode(String param, Integer count) {
        Integer lexicographicOrder = param.chars().sum();
        return lexicographicOrder & count;
    }

我们简单写一段测试代码测试下。
在这里插入图片描述
很好,我们已经可以通过字符串来进行哈希运算了。

1.2 散列表

我们回到正题,之所以要设计一个哈希函数本质上是为了我们可以将具有相同哈希值的元素划分到同一区域,那么有了依据我们就要深入的去想一下我们该如何分割区域。

  1. 首先既然我们是以余数作为元素区分依据,那么我们就应该有对应多的区域(n),这个区域应该是固定且支持随机访问的。回顾我们之前学过的数据结构,数组无疑是最符合这个特性的,这样我们就完成了散列表设计的第一步。
  2. 接下来我们需要选一个数据结构来存放划分到这个区域的元素,这个时候我们对于数据的访问应该是按照顺序依次进行,而且能够很好的支持数据增删的。基于这个需求,我们选用了链表作为元素存放的基础数据结构。

然后我们需要做的就是将数组和链表组装到一起,就像是这样:
在这里插入图片描述
这就是一个散列表的简单雏形,到这里我们已经做了三件事情:
3. 设计了一个可以精准计算元素分区的散列函数。
4. 使用支持随机访问的数组结构作为分区数据的目录
5. 使用链表结构用来存储已经分好区域的元素

接下来我们需要做的就是将这三个已经完成的事情组装到一起,用代码写一个简易的散列表:

public class MyHash {

    private LinkedList<String>[] linkedLists = new LinkedList[6];

    public MyHash() {
        for (int i = 0; i < linkedLists.length; i++) {
            if (linkedLists[i] == null) {
                linkedLists[i] = new LinkedList<>();
            }
        }
    }


    public Integer getHashCode(String param, Integer count) {
        Integer lexicographicOrder = param.chars().sum();
        return lexicographicOrder & count;
    }

    public Boolean put(String item) {
        Integer hashCode = getHashCode(item, linkedLists.length);
        linkedLists[hashCode].add(item);
        return Boolean.TRUE;
    }


    public String toString() {
        StringBuilder result = new StringBuilder();
        for (LinkedList<String> linkedList : linkedLists) {
            linkedList.forEach(item -> result.append(item + "\n"));
        }
        return result.toString();
    }


    public static void main(String[] args) {
        MyHash myHash = new MyHash();
        myHash.put("java");
        myHash.put("js");
        myHash.put("python");
        myHash.put("matlab");
        myHash.put("c++");
        myHash.put("c");
        System.out.println(myHash.toString());
    }
}

运行一下:
在这里插入图片描述

不过我们这个散列表的能力还很弱,很多实用的功能诸如去重,解决hash碰撞,根据负载因子动态扩容等功能都还没有实现,如果感兴趣的小伙伴可以自己动手试一下。

二、算法实战

2.1 两数之和

题目

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。

示例1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]

示例2:

输入: nums = [3,2,4], target = 6
输出: [1,2]

题解

1. 暴力破解

思路:
暴力枚举通常是我们解题时最常想到的方法,例如此题我们的目标是寻找相加等于target的两个数组元素。假设我们在遍历数组时的当前元素为currentValue,此时我们就需要再次去数组中遍历寻找一个值,此值等于target - currentValue ,若能找到则返回两个元素下标,若找不到则返回null。

代码:

/*枚举解法*/
private static int[] twoSumByExhaustion(int[] nums, int target) {
    for (int i = 0; i < nums.length; i++) {
        for (int j = i + 1; j < nums.length; j++) {
            if (nums[j] == target - nums[i]) {
                return new int[]{i, j};
            }
        }
    }
    return null;
}

复杂度分析:

  • 时间复杂度:O(N^2),其中 N 是数组中的元素数量。
  • 空间复杂度:O(1)。

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zmppqJYu-1668481560674)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/df0fd5e260ce4d3787809589a023ad65~tplv-k3u1fbpfcp-watermark.image?)]

2. hash表

思路:
由于本题并没有限制我们使用额外的内存空间,因此我们可以借助额外的内存空间存储数组中的元素以达到减少遍历次数的目的。

代码:

/*hash表解法*/
private static int[] twoSum(int[] nums, int target) {
    // 首先创建一个hash表
    Map<Integer, Integer> intMap = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        // 判断hash表中是否已经存有目标元素
        Integer integer = intMap.get(target - nums[i]);
        if (integer != null) {
            // 若有则返回坐标
            return new int[]{integer, i};
        }
        // 如没有则存放元素,继续遍历
        intMap.put(nums[i], i);
    }
    return null;
}

复杂度分析

  • 时间复杂度:O(N),其中 N 是数组中的元素数量。
  • 空间复杂度:O(N)。

运行结果:

结语

今天的内容就到此结束了,有疑问的小伙伴欢迎评论区留言或者私信博主,博主会在第一时间为你解答。
Leetcode刷题攻略已上传到gitee仓库,需要的小伙伴们可以自取:
https://gitee.com/xiaolong-oba/algorithm-and-data-structure

码字不易,感到有收获的小伙伴记得要关注博主一键三连,不要当白嫖怪哦~
如果大家有什么意见和建议请评论区留言或私聊博主,博主会第一时间反馈的哦。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

测试项目(MSTest)中涉及到读取App.config 操作(.net6)

文章目录环境问题排查过程查看Nuget包是否正确查看配置文件是否正确解决办法&#xff08;手动&#xff09;解决办法&#xff08;自动&#xff09;为什么是这样的呢&#xff1f;环境 VS2022MSTest项目.Net6版本 问题 在测试过程中发现读取App.config中的连接字符串是null&…

颜色杂项笔记

面向用户的HSV颜色模型的三个属性 面向用户的颜色模型HSV&#xff0c;有如下几个属性 Hue&#xff08;色度、色调、色相&#xff09;&#xff1a;描述具体颜色&#xff0c;比如红、蓝、黄、绿等&#xff0c;可以理解为color的专业说法。 Saturation&#xff08;饱和度&#xff…

红帽8使用nfs共享本地镜像

实验环境 FFF-server 192.168.80.100 SSS-client 192.168.80.254 实验前提关闭selinux和防火墙 第一步在开始之前我们可以先看一下nfs-server本地上的一个镜像挂载情况。如图1. 可以看到本地镜像已经被挂载上去。 第二步我们继续看一下server的yum仓库是否已经成功配置。如…

公布一小时下载量达10W:京东T5级架构师出品高并发核心编程手册

高并发有多重要&#xff1f; 高并发面试已经成了各大厂面试必问的题目&#xff0c;尤其是阿里、京东这样的大厂&#xff0c;面试的时候会往深了去问&#xff0c;可以说是你能回答出多少&#xff0c;你拿到大厂offer的概率就有多大&#xff01; 因高并发的问题回答不上来的案例…

采购软件能否降低企业采购成本?如何实现的?

在如今的疫情影响下&#xff0c;降低成本一直是企业决策者的主要目标之一&#xff0c;在采购领域尤其如此。而很多企业在销售业绩下滑时&#xff0c;纷纷通过采购软件来降低采购成本从而提升利润&#xff0c;达到了不可思议的效果。那么采购软件能否降低企业采购成本&#xff1…

ELK日志实时分析

项目实训报告&#xff1a;ELK日志实时分析 任务目标 使用filebeat采集日志数据&#xff0c;通过kafka将数据传输给logstash进行过滤&#xff0c;最后输出到Elasticsearch绘制数据图表。 数据说明 实施步骤 将数据上传到家目录&#xff08;/home/hadoop&#xff09;&#…

CentOS7.5虚拟机扩展xfs文件系统

1.目标 虚拟机xfs文件系统挂载点根目录&#xff08;也就是/dev/sda3&#xff09;扩展空间 2.软件版本 Vmware WorkStation 16pro CentOS7.5 3.外部硬盘增加空间 硬盘空间只能增大&#xff0c;不能缩小&#xff0c;最大磁盘大小必须大于现在的size&#xff0c;否则扩展按钮置灰…

JSON 学习(FastJson和Jackson)

JSON 学习 文章目录JSON 学习1. Json数据格式1.1 Json 数据格式1.2 Json 对象格式1.3 数组对象相互嵌套格式1.3.1 数组中的元素是对象1.3.2 对象中的值是数组1.3.3 你中有我&#xff0c;我中有你2. 使用场景3. java里面操作json有哪些技术4. Fastjson4.1 FastJson的优点4.2 Fas…

Spring Security认证之基本认证

本文内容来自王松老师的《深入浅出Spring Security》&#xff0c;自己在学习的时候为了加深理解顺手抄录的&#xff0c;有时候还会写一些自己的想法。 快速入门 在Spring Boot项目中使用Spring Security非常方便&#xff0c;创建一个新的Spring Boot项目我们只要引入Web和Spri…

java项目:前后端分离SpringBoot+Vue+Element的校内跑腿平台

收藏点赞不迷路 关注作者有好处 项目编号&#xff1a;BS-XX-155 一&#xff0c;项目简介 近年来&#xff0c;随着国内都市化的发展&#xff0c;生产生活节奏变快、各种往来频繁。经济的高速发展催生出“懒人经济”。不想走出家门&#xff0c;饭菜可以送上门;不方便交水、电、…

Java中restTemplate的使用

原文链接 代码地址 本文介绍restTemplate基础用法。 Java中get和post的用法请参考&#xff1a;https://mp.weixin.qq.com/s/mC0D1nuCqIori5bWtLorWQ 1 提供get/post接口 1.1 Controller RestController RequestMapping("/homepage") public class MyController…

电脑如何清理重复文件,查找电脑重复文件的软件

在电脑上面&#xff0c;不论是我们可以保存的&#xff0c;还是自动缓存的&#xff0c;都会有大量的重复文件&#xff0c;可能我们自己并没有发现&#xff0c;占据着电脑大量的空间&#xff0c;长此以往下去&#xff0c;会让电脑变得卡顿&#xff0c;我们就需要来清理一下这些不…

低代码维格云甘特视图入门教程

功能简介 低代码维格云甘特图主要通过条状图来显示某些时间相关的活动(任务、阶段、项目等)随着时间进展的情况,以便管理者直观地查看活动进度,把控全局。又称为时间视图、横道图、条状图(Bar chart)。 低代码维格云甘特图适用场景 项目管理生产管理其他领域:建筑、IT软件…

嵌入式FreeRTOS学习八,xTaskCreate创建任务的细节以及恢复中断任务实现

一.创建任务函数xTaskCreate 任务也不是很复杂的东西&#xff0c;任务也就是一个函数xTaskCreate。简单得说&#xff0c;创建一个任务&#xff0c;你得提供它的执行函数&#xff0c;你得提供它的栈的大小&#xff0c;函数的执行空间&#xff0c;函数的优先级等重要的条件。因为…

IPWorks EDI Translator Delphi Edition

IPWorks EDI Translator Delphi Edition 一套轻量级可编程EDI解析和翻译组件。 IPWorks EDI转换器包括便于电子数据交换(EDI)解析、翻译和验证的软件组件。这些组件包括灵活的模式支持&#xff0c;使开发人员能够使用各种模式格式&#xff0c;从而更容易与现有EDI处理应用程序集…

Maven项目属性与版本管理

本次将介绍两个内容&#xff0c;分别是&#xff1a; 属性版本管理 1. 属性 1.1 问题分析 我们先来分析一下问题&#xff1a; 前面在父工程中的dependencyManagement标签中对项目中所使用的jar包版本进行了统一的管理&#xff0c;但是如果在标签中有如下的内容&#xff1a;…

React源码分析4-深度理解diff算法

上一章中 react 的 render 阶段&#xff0c;其中 begin 时会调用 reconcileChildren 函数&#xff0c; reconcileChildren 中做的事情就是 react 知名的 diff 过程&#xff0c;本章会对 diff 算法进行讲解。 diff 算法介绍 react 的每次更新&#xff0c;都会将新的 ReactElem…

[安卓逆向]IDA Pro的认识及使用

[安卓逆向]IDA Pro的认识及使用 软件介绍 IDA Pro全称是交互式反汇编器专业版&#xff0c;人们其简称为IDA&#xff0c;IDA pro 是业界最成熟、先进的反汇编工具之一&#xff0c;是目前最棒的一个静态反编译软件&#xff0c;为众多0day世界的成员和ShellCode安全分析人士不可…

指纹浏览器是什么?可以用来解决流量套利的什么问题?

套利是一个永远不会过期的形式&#xff0c;由于信息差永远存在&#xff0c;有信息差就有套利空间。流量套利是购买和转售流量的过程。套利专家通常通过购买廉价流量并以更好的价格出售来赚取收入。他们把流量导流到广告商的网站上&#xff0c;满足广告商希望客户访问自己的网站…

理解Linux权限(一)

理解Linux文件权限 Permission Groups(权限组) 根据权限组划分&#xff1a;每个文件和目录都有3种使用者(用户) ower(所有者) - 所有者的权限仅适用于文件和目录的所有者&#xff0c;不会影响其他用户的操作&#xff1b;group(所属组) - 所属组的权限仅适用于已分配的文件和…