Day_42哈希表

news/2024/5/20 12:31:46/文章来源:https://blog.csdn.net/DARRENANJIAN/article/details/131036977

目录

一. 关于哈希表

二. 如何实现哈希表

        1. 散列函数

        2. 散列表

        3. 散列函数的构造方法

        4. 处理冲突的方法

三. 代码实现

        1. 构造函数构造哈希表

        2. 哈希表的查找

四. 代码展示

五. 数据测试​编辑

六. 总结


一. 关于哈希表

        在前面介绍的线性表的查找中,记录在表中的位置与记录的关键字之间不存在确定关系,因此,在这些表中查找记录时需进行一系列的关键字比较。这类查找方法建立在“比较”的基础上,查找的效率取决于比较的次数。

二. 如何实现哈希表

        1. 散列函数

        一个把查找表中的关键字映射成该关键字对应的地址的函数,记为Hash(key)=Addr(这里的地址可以是数组下标、有索引或内存地址等)。散列函数可能会把两个或两个以上的不同关键字映射到同一地址,称这种情况为冲突,这些发生碰撞的不同关键字称为同义词。一方面, 设计得好的散列函数应尽量减少这样的冲突;另一方面,由于这样的冲突总是不可避免的,所以还要设计好处理冲突的方法。

        2. 散列表

        根据关键字而直接进行访问的数据结构。也就是说,散列表建立了关键字和存储地址之间的一种直接映射关系。理想情况下,对散列表进行查找的时间复杂度为0(1),即与表中元素的个数无关。下面分别介绍常用的散列函数和处理冲突的方法。

构造完成的哈希表

        3. 散列函数的构造方法

        1)散列函数的定义域必须包含全部需要存储的关键字,而值域的范围则依赖于散列表的大小或地址范围。

        2)散列函数计算出来的地址应该能等概率。均匀的分布在整个地址空间中,从而减少冲突的发生。

        3)散列函数应尽量简单,能够在较短的时间内计算出任意一个关键字对应的散列地址。

        以下是常用的散列函数:

        H(key)=a\times key+b

H(key)=key\%p

        4. 处理冲突的方法

        线性探测法:冲突发生时,顺序查看表中下一个单元(探测到表尾地址m-1时,下一个探测地址是表首地址0),直到找出下一个空闲单元(当表未填满时一定能找到一个空闲单元)或查遍全表。线性探测法可能使第i个散列地址的同义词存入第i+1个散列地址,这样本应该存入i+1个散列地址的元素就争夺i+2个散列地址的元素地址...从而造成大量元素在相邻的散列地址上堆积起来,大大降低了查找效率。

        除此之外再介绍一种拉链法处理冲突:当我们的同义词发生冲突之后,可以把所有的同义词存储在一个线性链表中,这个线性链表由其散列地址唯一标识。假设散列地址i的同义词链表的头指针存放在散列表的第i个单元中,因而查找、插入、删除操作主要在同义词链中进行。例如散列函数Hash(key)=key%13,用拉链法处理冲突建立如下的哈希表

        

拉链法处理冲突

        还有平方探测法,双散列法,伪随机探测法在这里就不一一赘述。

三. 代码实现

        1. 构造函数构造哈希表

        在这里设置了一个新的构造函数,传入标签数组paraKeyArray,对应的数据数组paraContentArray,还有哈希表长度paraLength。构造一个长度为paraLength的数组,每个位置上是用哈希函数得到的节点值。

    /************************ The second constructor. For Hash code only. It is assumed that* paraKeyArray.length <= paraLength.** @param paraKeyArray     The array of the keys.* @param paraContentArray The array of contents.* @param paraLength       The space for the Hash table.**********************/public DataArray(int[] paraKeyArray, String[] paraContentArray, int paraLength) {// Step 1. Initialize.length = paraLength;data = new DataNode[length];for (int i = 0; i < length; i++) {data[i] = null;} // Of for i// Step 2. Fill the data.int tempPosition;for (int i = 0; i < paraKeyArray.length; i++) {// Hash.tempPosition = paraKeyArray[i] % paraLength;// Find an empty positionwhile (data[tempPosition] != null) {tempPosition = (tempPosition + 1) % paraLength;System.out.println("Collision, move forward for key " + paraKeyArray[i]);} // Of whiledata[tempPosition] = new DataNode(paraKeyArray[i], paraContentArray[i]);} // Of for i}// Of the second constructor

        2. 哈希表的查找

        构建完成哈希表之后,开始查找,输入需要查找的标签i,先查找i%paraLength的位置是不是i;若不是则将i自加1,再用(i+1)%paraLength查找第二个位置;继续如上循环直到查找到为止。

    /************************ Hash search.** @param paraKey The given key.* @return The content of the key.**********************/public String hashSearch(int paraKey) {int tempPosition = paraKey % length;while (data[tempPosition] != null) {if (data[tempPosition].key == paraKey) {return data[tempPosition].content;} // Of ifSystem.out.println("Not this one for " + paraKey);tempPosition = (tempPosition + 1) % length;} // Of whilereturn "null";}// Of hashSearch

四. 代码展示

        主类

package Day_42;import Day_41.DataArray;public class demo1 {/************************ The entrance of the program.** @param args Not used now.**********************/public static void main(String args[]) {
//        System.out.println("\r\n-------sequentialSearchTest-------");int []paraKeyArray;paraKeyArray=new int[]{1,2,3};String[] paraContentArray = new String[]{"121","21","324"};DataArray test=new DataArray(paraKeyArray,paraContentArray);test.hashSearchTest();}// Of main}

        调用类:

package Day_41;
/*** Data array for searching and sorting algorithms.** @author Jian An 2569222191@qq.com.*/
public class DataArray {/*** An inner class for data nodes. The text book usually use an int value to* represent the data. I would like to use a key-value pair instead.*/class DataNode {/*** The key.*/int key;/*** The data content.*/String content;/*** ********************* The first constructor.* *********************/DataNode(int paraKey, String paraContent) {key = paraKey;content = paraContent;}// Of the first constructor/*** ********************* Overrides the method claimed in Object, the superclass of any class.* *********************/public String toString() {return "(" + key + ", " + content + ") ";}// Of toString}// Of class DataNode/*** The data array.*/DataNode[] data;/*** The length of the data array.*/int length;/*** ********************* The first constructor.** @param paraKeyArray     The array of the keys.* @param paraContentArray The array of contents.*                         *********************/public DataArray(int[] paraKeyArray, String[] paraContentArray) {length = paraKeyArray.length;data = new DataNode[length];for (int i = 0; i < length; i++) {data[i] = new DataNode(paraKeyArray[i], paraContentArray[i]);} // Of for i}// Of the first constructor/*** ********************* Overrides the method claimed in Object, the superclass of any class.* *********************/public String toString() {String resultString = "I am a data array with " + length + " items.\r\n";for (int i = 0; i < length; i++) {resultString += data[i] + " ";} // Of for ireturn resultString;}// Of toString/*** ********************* Sequential search. Attention: It is assume that the index 0 is NOT used.** @param paraKey The given key.* @return The content of the key.* *********************/public String sequentialSearch(int paraKey) {data[0].key = paraKey;int i;// Note that we do not judge i >= 0 since data[0].key = paraKey.// In this way the runtime is saved about 1/2.// This for statement is equivalent to//for (i = length - 1; data[i].key != paraKey; i--);for (i = length - 1; data[i].key != paraKey; i--) {;}//Of for ireturn data[i].content;}// Of sequentialSearch/*** ********************* Test the method.* *********************/public static void sequentialSearchTest() {int[] tempUnsortedKeys = {-1, 5, 3, 6, 10, 7, 1, 9};String[] tempContents = {"null", "if", "then", "else", "switch", "case", "for", "while"};DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);System.out.println(tempDataArray);System.out.println("Search result of 10 is: " + tempDataArray.sequentialSearch(10));System.out.println("Search result of 5 is: " + tempDataArray.sequentialSearch(5));System.out.println("Search result of 4 is: " + tempDataArray.sequentialSearch(4));}// Of sequentialSearchTest/*** ********************* Binary search. Attention: It is assume that keys are sorted in ascending* order.** @param paraKey The given key.* @return The content of the key.* *********************/public String binarySearch(int paraKey) {int tempLeft = 0;int tempRight = length - 1;int tempMiddle = (tempLeft + tempRight) / 2;while (tempLeft <= tempRight) {tempMiddle = (tempLeft + tempRight) / 2;if (data[tempMiddle].key == paraKey) {return data[tempMiddle].content;} else if (data[tempMiddle].key <= paraKey) {tempLeft = tempMiddle + 1;} else {tempRight = tempMiddle - 1;}} // Of while// Not found.return "null";}// Of binarySearch/*** ********************* Test the method.* *********************/public static void binarySearchTest() {int[] tempSortedKeys = {1, 3, 5, 6, 7, 9, 10};String[] tempContents = {"if", "then", "else", "switch", "case", "for", "while"};DataArray tempDataArray = new DataArray(tempSortedKeys, tempContents);System.out.println(tempDataArray);System.out.println("Search result of 10 is: " + tempDataArray.binarySearch(10));System.out.println("Search result of 5 is: " + tempDataArray.binarySearch(5));System.out.println("Search result of 4 is: " + tempDataArray.binarySearch(4));}// Of binarySearchTest/************************ The second constructor. For Hash code only. It is assumed that* paraKeyArray.length <= paraLength.** @param paraKeyArray     The array of the keys.* @param paraContentArray The array of contents.* @param paraLength       The space for the Hash table.**********************/public DataArray(int[] paraKeyArray, String[] paraContentArray, int paraLength) {// Step 1. Initialize.length = paraLength;data = new DataNode[length];for (int i = 0; i < length; i++) {data[i] = null;} // Of for i// Step 2. Fill the data.int tempPosition;for (int i = 0; i < paraKeyArray.length; i++) {// Hash.tempPosition = paraKeyArray[i] % paraLength;// Find an empty positionwhile (data[tempPosition] != null) {tempPosition = (tempPosition + 1) % paraLength;System.out.println("Collision, move forward for key " + paraKeyArray[i]);} // Of whiledata[tempPosition] = new DataNode(paraKeyArray[i], paraContentArray[i]);} // Of for i}// Of the second constructor/************************ Hash search.** @param paraKey The given key.* @return The content of the key.**********************/public String hashSearch(int paraKey) {int tempPosition = paraKey % length;while (data[tempPosition] != null) {if (data[tempPosition].key == paraKey) {return data[tempPosition].content;} // Of ifSystem.out.println("Not this one for " + paraKey);tempPosition = (tempPosition + 1) % length;} // Of whilereturn "null";}// Of hashSearch/************************ Test the method.**********************/public static void hashSearchTest() {int[] tempUnsortedKeys = { 16, 33, 38, 69, 57, 95, 86 };String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents, 19);System.out.println(tempDataArray);System.out.println("Search result of 95 is: " + tempDataArray.hashSearch(95));System.out.println("Search result of 38 is: " + tempDataArray.hashSearch(38));System.out.println("Search result of 57 is: " + tempDataArray.hashSearch(57));System.out.println("Search result of 4 is: " + tempDataArray.hashSearch(4));}// Of hashSearchTest}// Of class DataArray

五. 数据测试

六. 总结

        这一小节的代码比较简单,这一节的知识体现不在代码上,而在于构造哈希函数,处理冲突方法的结构上。一个好的哈希表处理查找的效率是O(1),即瞬间可以得到传入标签的数据值,这在我们无论哪一个查找算法中无疑都是最快的。但是缺点也还是有的,若构造哈希函数没有构造好,或者冲突的没有处理好,那将造成大范围的“聚集”现象,大大降低查找效率。

        除此之外,现目前很多的编程环境已经自带了哈希表的包,例如哈希表在JDK中有不少的实现,例如HahsMapHashTable等,对哈希表感兴趣的可以阅读本文后去查看JDK的相应实现,相信这可以增强你对哈希表的理解。

        

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

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

相关文章

kali 2023.2安装、换源、更新、SSH

kali2023版本已经更新了&#xff0c;为了体验新版&#xff0c;下载试用了一下。记录初始的安装过程&#xff0c;以备复习用&#xff0c;不足之处欢迎批评指正。 一、下载 1、官网下载&#xff0c;地址&#xff1a;https://www.kali.org/&#xff0c;因为我准备在VM虚拟机中使用…

二叉搜索树(Binary Seach Tree)模拟实现

目录 二叉搜索树的性质 二叉搜索树的实现 结点类 接口类(BSTree) 二叉搜索树的插入(insert) 二叉搜索树的查找(find) 二叉搜索树删除(erase) 第二种、删除的结点右子树为空 第三种、删除的结点左子树为空 第四种、删除的结点左右都不为空 实现 二叉搜索树模拟实现代…

【算法】手写题

文章目录 画一个三角形实现三栏布局通过position和margin通过float和margin通过flex实现 变量提升题实现边框0.5px深拷贝快速排序 画一个三角形 .box1 {width: 0;height: 0;border: 10px solid;border-color: red transparent transparent transparent;}实现三栏布局 三栏布局…

深入浅出之Docker Compose详解

目录 1.Docker Compose概述 1.1 Docker Compose 定义 1.2 Docker Compose产生背景 1.3 Docker Compose 核心概念 1.4 Docker Compose 使用步骤 1.5 Docker Compose 常用命令 2. Docker Compose 实战 2.1 Docker Compose下载和卸载 2.2 Docker Compose 项目概述 2.3 Do…

呈现视觉妙技:使用Python将MP4视频转化为迷人的GIF图像

前言 GIF图片对于我来说是一个很好的展示方式&#xff0c;GIF 图片能够展示动态的图像效果&#xff0c;对于展示计算机视觉算法或结果非常有用。例如&#xff0c;我可以使用 GIF 图片来展示运动跟踪、姿势识别、图像分割、目标检测等任务的结果&#xff0c;以更生动和直观的方…

20230606夏新(Amoi)的4K显示器D320B2000的亮点检测

20230606夏新&#xff08;Amoi&#xff09;的4K显示器D320B2000的亮点检测 2023/6/7 0:14 https://item.jd.com/63690000655.html 夏新&#xff08;Amoi&#xff09;电脑显示器高清家用办公电竞吃鸡游戏液晶监控直播大屏便携显示屏幕 32英寸【直面 4k/144hz双模式 全面屏】黑 …

总结891

学习目标&#xff1a; 月目标&#xff1a;6月&#xff08;线性代数强化9讲1遍&#xff0c;背诵15篇短文&#xff0c;考研核心词过三遍&#xff09; 周目标&#xff1a;线性代数强化1讲&#xff0c;英语背3篇文章并回诵&#xff0c;检测 每日必复习&#xff08;5分钟&#xff…

Day_40关于图的总结

一. 实际问题的抽象与建模 如果我们需要研究一个实际问题&#xff0c;首先第一步就是对这个实际问题进行抽象&#xff0c;抽象是从众多的事物中抽取出共同的、本质性的特征&#xff0c;而舍弃其非本质的特征的过程。具体地说&#xff0c;抽象就是人们在实践的基础上&#xff0c…

chatgpt赋能python:Python如何自动换行

Python如何自动换行 在Python编程中&#xff0c;有时候我们需要输出很长的文本或字符串&#xff0c;这时候就需要自动换行的功能。本文将介绍Python中实现自动换行的几种方法。 方法一&#xff1a;使用字符拼接 在Python中&#xff0c;我们可以使用"“来拼接字符串。如…

Internal error. Please report to https://jb.gg/ide/critical-startup-errors

大佬的解决方式&#xff1a;PyCharm 2023 启动报错的处理 部分同学&#xff0c;发现在安装 PyCharm 2023.1.2 以及 PyCharm 2023.2 的抢先体验版之后&#xff0c;运行的时候愣是直接弹出了类似上面的报错。 反正&#xff0c;别慌&#xff01; 是的&#xff0c;他们有 bug。 …

【Java】深入理解Java虚拟机 | 垃圾收集器GC

《深入理解Java虚拟机》的阅读笔记——第三章 垃圾收集器与内存分配策略。 参考了JavaGuide网站的相关内容&#xff1a;https://javaguide.cn/ Q&#xff1a;哪些内存需要回收&#xff1f;什么时候回收&#xff1f;如何回收&#xff1f; 2 对象已死吗&#xff1f; 2.1 引用…

剪映自动打关键帧

牙叔教程 简单易懂 这是给单张图片打关键帧的教程, 给图片打关键帧有四个步骤 鼠标点选图片打起始帧跳转到图片末尾打结束帧 打帧是一件很费手的事情, 所以我写了个自动化的代码, 专门用来打关键帧, 使用的软件是 AutoHotkey 关键帧参数的详细解释 剪映 自动打关键帧 AutoH…

Azure Log Analytics:与Power BI集成

注&#xff1a;本文最初发布于https://d-bi.gitee.io, 2023年6月迁移至CSDN 前述 Azure Log Analytics是Azure Monitor中的一项分析服务。本文将讲述通过Log Analytics与Power BI集成的方式&#xff0c;获取Power BI工作区内的日志信息&#xff0c;包括各PBI数据集的CPU消耗&a…

Web安全总结

目录 网站架构一般web服务器结构相比于传统的网络攻击&#xff0c;基于web的攻击有什么不同&#xff1f;HTTP协议HTTP响应拆分攻击HTTPS针对HTTPS协议的攻击那么如何保证证书的唯一性&#xff1f; HTTP会话Cookie和Session的关系HTTP会话攻击解决方案 Web访问中的隐私问题Web应…

chatgpt赋能python:Python如何空一行:介绍

Python如何空一行&#xff1a;介绍 在Python编程中&#xff0c;经常需要在输出文字或代码时进行空行分隔。一个常用的场景就是在代码中加入注释&#xff0c;将注释与代码分开&#xff0c;使代码逻辑更加清晰易懂。在某些情况下&#xff0c;也需要在输出文字时进行空行分割&…

ChatGPT-Plugins-Searchable

ChatGPT Plus 用户应该都知道Plus已经开放了插件功能&#xff0c;但是在插件商店里存在一个较大的问题插件数量超过100款&#xff0c;却没有便捷的搜索功能。 而我们在查找一款插件时&#xff0c;需要从插件商店的第一页点击到最后一页一个个找&#xff0c;显然这非常的麻烦。 …

JUC基础-0606

9.ReentrantReadWriteLock读写锁 9.1 锁的基本概念 悲观锁&#xff1a;不支持并发&#xff0c;效率低&#xff0c;但是可以解决所有并发安全问题 乐观锁&#xff1a;支持并发读&#xff0c;维护一个版本号&#xff0c;写的时候比较版本号进行控制&#xff0c;先提交的版本号…

【Vue】三:Vue组件: 组件使用和组件嵌套

文章目录 1.第一个组件1.1不使用组件前1.2创建组件1.3注册组件1.4使用组件1.5 细节 2.组件嵌套 1.第一个组件 1.1不使用组件前 1.2创建组件 Vue.extends({该配置项和new Vue的配置项几乎相同})区别&#xff1a; &#xff08;1&#xff09;创建Vue组件的时候&#xff0c;不能使…

Kubernetes之pod

Kubernetes之pod 在通过docker运行程序时&#xff0c;我们通常会制作Dockerfile文件构建镜像。也可以基于某个镜像运行容器在容器中安装组件之后&#xff0c;再基于容器生成镜像 使用如下命令可生成镜像&#xff0c;想了解更多参数请添加–help docker build -f Dockerfile路…

【Leetcode -138.复制带随机指针的链表 -2130.链表最大孪生和】

Leetcode Leetcode -138.复制带随机指针的链表Leetcode -2130.链表最大孪生和 Leetcode -138.复制带随机指针的链表 题目&#xff1a;给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构…