哈希表,哈希桶及配套习题

我们今天带大家简单了解哈希表是怎样的,和简单模拟哈希桶,还有几道练习题

一,哈希表

什么是哈希表,哈希表是一种非常非常高效的数据结构,它用来搜索我们想要的数据,我们之前学过很多查找方法,最快基本时间复杂度就是Olog2(n),哈希表可以达到O(1);这是怎么做到的呢,因为哈希表的查找并不是遍历,或是递归,而是根据哈希函数来计算这个数据应该存放的地址,取出时也通过哈希函数拿出我们的元素。

1,哈希函数

我们怎么去设计哈希函数呢,说实话这不是我们能设计的,我们拿来用就好了。

(1)index = y % capacity;

容量我们可以当做数组长度,y就是我们输入的数字,index就是我们获得的新的下标。

我们后面哈希桶用这个方法。

我们比如capacity =10,y为7,那么Index就为7,我们把7放到数组7下标,但是我们方17,17%10=7,那我们还是放到7下标吗,这就引出了哈希冲突。

2,哈希冲突

哈希冲突指的是我们在使用哈希函数时,计算的几个函数的地址都相同,我们叫它哈希冲突或者哈希碰撞,我们无法正常使用我们的数组来搜索对应的函数了。

3,哈希冲突的避免

有问题就要解决,我们如何避免哈希冲突呢,哈希冲突的发生是必然的,我们既然根据刚才的哈希函数,可以知道,添加数据越多,哈希冲突发生概率越大,那我们就可以扩容,降低哈希冲突的发生概率,我们还可以改变哈希函数,

常见哈希函数

1. 直接定制法--(常用)

取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B 优点:简单、均匀 缺点:需要事先知道关 键字的分布情况 使用场景:适合查找比较小且连续的情况

2. 除留余数法--(常用)

设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数: Hash(key) = key% p(p<=m),将关键码转换成哈希地址

3. 平方取中法--(了解)

假设关键字为1234,对它平方就是1522756,抽取中间的3位227作为哈希地址; 再比如关键字为4321,对 它平方就是18671041,抽取中间的3位671(或710)作为哈希地址 平方取中法比较适合:不知道关键字的分 布,而位数又不是很大的情况

4. 折叠法--(了解)

折叠法是将关键字从左到右分割成位数相等的几部分(最后一部分位数可以短些),然后将这几部分叠加求和, 并按散列表表长,取后几位作为散列地址。 折叠法适合事先不需要知道关键字的分布,适合关键字位数比较多的情况

5. 随机数法--(了解)

选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key) = random(key),其中random为随机数 函数。 通常应用于关键字长度不等时采用此法

6. 数学分析法--(了解)

设有n个d位数,每一位可能有r种不同的符号,这r种不同的符号在各位上出现的频率不一定相同,可能在某 些位上分布比较均匀,每种符号出现的机会均等,在某些位上分布不均匀只有某几种符号经常出现。可根据 散列表的大小,选择其中各种符号分布均匀的若干位作为散列地址。例如: 假设要存储某家公司员工登记表,如果用手机号作为关键字,那么极有可能前7位都是 相同的,那么我们可以 选择后面的四位作为散列地址,如果这样的抽取工作还容易出现 冲突,还可以对抽取出来的数字进行反转(如 1234改成4321)、右环位移(如1234改成4123)、左环移位、前两数与后两数叠加(如1234改成12+34=46)等方 法。 数字分析法通常适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关键字的若干位分布较均 匀的情况

4,负载因子

我们刚才谈过了,负载因子就是填入表中的个数 / 散列表长度,我们通常控制负载因子在7.5,超过7.5,冲突率发生的概率就大大提升。

5,解决冲突

解决冲突的方法分两种,开散列和闭散列,

我们这里重点掌握哈希桶,

哈希桶是啥意思,哈希桶是存放哈希元素冲突元素的地方。

我们通常在每个哈希表的下标中放入链表来延长每个哈希表下标的元素,比如4,44,14,我们都存在4下标的一个链表中。

我们来模拟实现一下。

public class HashBucket<K,V> {private static class Node<K,V> {private K key;private V value;Node<K,V> next;public Node(K key, V value) {this.key = key;this.value = value;}}private Node<K,V>[] array = (Node<K, V>[]) new Node[DEFAULT_SIZE];private int size;   // 当前的数据个数private static final double LOAD_FACTOR = 0.75;private static final int DEFAULT_SIZE = 10;//默认桶的大小public void put(K key, V value) {Node<K,V> newNode = new Node<>(key, value);int index = key.hashCode() % array.length;Node<K,V> cur = array[index];Node<K,V> p = null;if(cur==null){array[index] = newNode;size++;if (loadFactor()>LOAD_FACTOR){resize();}}else {while (cur!=null){if(cur.key.equals(key)){cur.value = value;return;}p = cur;cur = cur.next;}p.next = newNode;size++;if (loadFactor()>LOAD_FACTOR){resize();}}}private void resize() {Node<K,V>[] newArray = (Node<K, V>[]) new Node[2*array.length];Node<K,V> cur = null;Node<K,V> p = null;for (int i = 0; i < array.length; i++) {cur = array[i];while (cur!=null){int newIndex = cur.key.hashCode() % newArray.length;p = cur.next;cur.next = newArray[newIndex];newArray[newIndex] = cur;cur = p;}}array = newArray;}private double loadFactor() {return size * 1.0 / array.length;}public V get(K key) {Node<K,V> cur = null;int index = key.hashCode() % array.length;cur = array[index];while (cur!=null){if(cur.key.equals(key)){return cur.value;}}return null;}
}

我们来练几道题

二,题目练习

138. 随机链表的复制 - 力扣(LeetCode)

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。

你的代码  接受原链表的头节点 head 作为传入参数。

示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

示例 2:

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]

示例 3:

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]

代码实现: 

class Solution {public Node copyRandomList(Node head) {Map<Node,Node> map = new HashMap<>();Node cur = head;while(cur!=null){//遍历链表,将链表的每个节点放到key复制一份放到valuemap.put(cur,new Node(cur.val));cur = cur.next;}cur = head;while(cur!=null){//再次遍历链表,用map找到每次创建的新节点,在通过map找到其next,random需要指向的节点。map.get(cur).next = map.get(cur.next);map.get(cur).random = map.get(cur.random);cur = cur.next;}return map.get(head);}
}

 

链接:旧键盘 (20)__牛客网
来源:牛客网

旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出
肯定坏掉的那些键。

输入描述:
输入在2行中分别给出应该输入的文字、以及实际被输入的文字。每段文字是不超过80个字符的串,由字母A-Z(包括大、小写)、数字0-9、
以及下划线“_”(代表空格)组成。题目保证2个字符串均非空。
输出描述:
按照发现顺序,在一行中输出坏掉的键。其中英文字母只输出大写,每个坏键只输出一次。题目保证至少有1个坏键。

示例1

输入

7_This_is_a_test<br/>_hs_s_a_es

输出

7TI

代码示例:

import java.util.Scanner;
import java.util.*;// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);String input = in.nextLine();input = input.toUpperCase();String output = in.nextLine();output = output.toUpperCase();Map<Character,Integer> map = new HashMap<>();for(int i=0;i<output.length();i++){char a = output.charAt(i);if(map.get(a)==null){map.put(a,1);}else{map.put(a,map.get(a)+1);}}for(int i=0;i<input.length();i++){char w = input.charAt(i);if(map.get(w)==null){System.out.print(w);map.put(w,1);}}}
}

给你一个字符串 jewels 代表石头中宝石的类型,另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。

字母区分大小写,因此 "a" 和 "A" 是不同类型的石头。

771. 宝石与石头 - 力扣(LeetCode)

示例 1:

输入:jewels = "aA", stones = "aAAbbbb"
输出:3

示例 2:

输入:jewels = "z", stones = "ZZ"
输出:0

提示:

  • 1 <= jewels.length, stones.length <= 50
  • jewels 和 stones 仅由英文字母组成
  • jewels 中的所有字符都是 唯一的

代码示例:

class Solution {public int numJewelsInStones(String jewels, String stones) {Map<Character,Integer> map = new HashMap<>();for(int i=0;i<jewels.length();i++){char c = jewels.charAt(i);map.put(c,1);}int count = 0;for(int i=0;i<stones.length();i++){char c = stones.charAt(i);if(map.get(c)!=null){count++;}}return count;}
}

 

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

136. 只出现一次的数字 - 力扣(LeetCode)

示例 1 :

输入:nums = [2,2,1]
输出:1

示例 2 :

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

示例 3 :

输入:nums = [1]
输出:1提示:
  • 1 <= nums.length <= 3 * 104
  • -3 * 104 <= nums[i] <= 3 * 104
  • 除了某个元素只出现一次以外,其余每个元素均出现两次.

代码示例: 

class Solution {public int singleNumber(int[] nums) {//方法1// int num = nums[0];// for(int i=1;i<nums.length;i++){//     num = num ^ nums[i];// }// return num;//方法2Map<Integer,Integer> map = new HashMap<>();for(int i=0;i<nums.length;i++){if(map.get(nums[i])==null){map.put(nums[i],1);}else{map.put(nums[i],map.get(nums[i])+1);}}for(int i=0;i<nums.length;i++){if(map.get(nums[i])==1){return nums[i];}}return -1;}
}

 

 

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

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

相关文章

二百七十四、Kettle——ClickHouse中对错误数据表中进行数据修复(实时)

一、目的 在完成数据清洗、错误数据之后&#xff0c;需要根据修复规则对错误数据进行修复 二、Hive中原有代码 insert into table hurys_db.dwd_queue partition(day) selecta3.id,a3.device_no,a3.source_device_type,a3.sn,a3.model,a3.create_time,a3.lane_no,a3.lane_…

Golang | Leetcode Golang题解之第530题二叉搜索树的最小绝对差

题目&#xff1a; 题解&#xff1a; func getMinimumDifference(root *TreeNode) int {ans, pre : math.MaxInt64, -1var dfs func(*TreeNode)dfs func(node *TreeNode) {if node nil {return}dfs(node.Left)if pre ! -1 && node.Val-pre < ans {ans node.Val -…

Android Studio打包时不显示“Generate Signed APK”提示信息

Android Studio打包时&#xff0c;默认显示“Generate Signed APK”提示信息&#xff0c;如下图所示&#xff1a; 如果在打包时不显示“Generate Signed APK”提示信息&#xff0c;解决办法是&#xff1a; Android Studio菜单栏&#xff0c;“File->Settings->Appearan…

手游和应用出海资讯:可灵AI独立APP即将上架;Rollic在英国推出芭比合并解谜手游

NetMarvel帮助游戏和应用广告主洞察全球市场、获取行业信息&#xff0c;以下为10月第四周资讯&#xff1a; ● 苹果开发全新游戏中心应用 ● Meta计划开发人工智能搜索引擎 ● 微软已拥有20个游戏IP&#xff0c;收入达10亿美元 ● OpenAI计划在12月推出其下一代前沿模型Orion ●…

js中多let与var

在 JavaScript 中&#xff0c;let 和 var 都用于声明变量&#xff0c;但它们有一些关键的区别。主要区别包括作用域、变量提升、可重复声明、以及在全局作用域中的行为。 1. 作用域&#xff08;Scope&#xff09; let&#xff1a;块级作用域。用 let 声明的变量只在其所在的代…

qt管理系统框架(好看界面、漂亮界面、好看的界面、漂亮的界面)

概述 最近一个项目用QT开发&#xff0c;然后找了美工帮设计了下界面。总算完工&#xff0c;后想一下干脆抽出一个基础框架&#xff0c;方便以后用。 功能 支持mysql、echarts。 支持加载动态权限菜单&#xff0c;轻松权限控制。 支持遮罩对话框、抽屉 支持开机启动动画界面 内…

华为云计算知识总结——及案例分享

目录 一、华为云计算基础知识二、华为云计算相关案例实战案例一&#xff1a;搭建弹性云服务器&#xff08;ECS&#xff09;并部署Web应用案例二&#xff1a;构建基于OBS的图片存储和分发系统案例三&#xff1a;基于RDS的高可用数据库应用案例四&#xff1a;使用华为云DDoS防护保…

11.1组会汇报-基于区块链的安全多方计算研究现状与展望

基础知识 *1.背书&#xff0c;这个词源来自银行票据业务&#xff0c;是指票据转让时&#xff0c;原持有人在票据背面加盖自己的印鉴&#xff0c;证明该票据真实有效、如果有问题就可以找原持有人。 区块链中的背书就好理解了。可以简单的理解为验证交易并声明此交易合法&…

【Linux】进程间通信(命名管道、共享内存、消息队列、信号量)

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;Linux 创作时间 &#xff1a;2024年11月2日 命名管道&#xff1a; 如果我们想在不相关的进程之间交换数据&#xff0c;可以使用FIFO文件来做这项工作&#xff0c;它经常被称为命名管道。命名管道是一种特殊类型的文…

划界与分类的艺术:支持向量机(SVM)的深度解析

划界与分类的艺术&#xff1a;支持向量机&#xff08;SVM&#xff09;的深度解析 1. 引言 支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是机器学习中的经典算法&#xff0c;以其强大的分类和回归能力在众多领域得到了广泛应用。SVM通过找到最优超平面来分…

Java设计模式(代理模式整理中ing)

一、代理模式 1、代理模式定义&#xff1a; 代理模式&#xff1a;由于某些原因要给某对象提供一个代理以控制对该对象的访问&#xff0c;这时访问对象不适合或者不能够直接引用目标对象&#xff0c;代理对象作为访问对象与目标对象之间的中介进行连接调控调用。 2、代理模式的…

【含文档+源码】基于SpringBoot+Vue的新型吃住玩一体化旅游管理系统的设计与实现

开题报告 本文旨在探讨新型吃住玩一体化旅游管理系统的设计与实现。该系统融合了用户注册与登录、旅游景点管理、旅游攻略发帖、特色旅游路线推荐、附近美食推荐以及酒店客房推荐与预定等多项功能&#xff0c;旨在为游客提供全方位、一体化的旅游服务体验。在系统设计中&#…

如何卸载电脑上的软件?彻底删除第三方和系统自带软件方法!(新款)

如何卸载电脑上的软件&#xff1f;在日常使用电脑的过程中&#xff0c;我们经常会安装各种软件以满足不同的需求。然而&#xff0c;随着时间的推移&#xff0c;一些不再使用的软件可能会占用系统资源&#xff0c;影响电脑性能。因此&#xff0c;定期卸载不需要的软件是保持系统…

cocos开发QA

目录 TS相关foreach循环中使用return循环延迟动态获取类属性 Cocos相关属性检查器添加Enum属性使用Enum报错 枚举“XXX”用于其声明前实现不规则点击区域使用cc.RevoluteJoint的enable激活组件无效本地存储以及相关问题JSON.stringify(map)返回{}数据加密客户端复制文本使用客户…

LeetCode :21. 合并两个有序链表(Java)

目录 题目描述: 代码: 第一种: 第二种: 题目描述: 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]示例 2&#xff1a; …

删除的文件怎么找回?删除文件恢复全面指南

我们常常在日常生活或工作中不小心删除了重要文件&#xff0c;这样的情况可能瞬间让人感到无助。不过&#xff0c;数据恢复技术已相当成熟&#xff0c;我们可以通过多种方法来找回误删的文件。下面我们将从简单到复杂逐步讲解找回删除文件的方法&#xff0c;希望可以帮助大家在…

D57【python 接口自动化学习】- python基础之异常

day57 异常捕获 学习日期&#xff1a;20241103 学习目标&#xff1a;异常 -- 73 异常捕获&#xff1a;出现异常时&#xff0c;如何利用程序进行处理&#xff1f; 学习笔记&#xff1a; try-except代码块 # 捕获异常 num1 num10 try:num/num1except Exception as e:print(上…

【06】A-Maven项目SVN设置忽略文件

做Web项目开发时&#xff0c;运用的是Maven管理工具对项目进行管理&#xff0c;在项目构建的过程中自动生成了很多不需要SVN进行管理的文件&#xff0c;SVN在对源码进行版本管理时&#xff0c;需要将其忽略&#xff0c;本文给出了具体解决方案。 SVN设置忽略Maven项目中自动生成…

logback日志级别动态切换四种方案

生产环境中经常有需要动态修改日志级别。 现在就介绍几种方案 方案一&#xff1a;开启logback的自动扫描更新 配置如下 <?xml version"1.0" encoding"UTF-8"?> <configuration scan"true" scanPeriod"60 seconds" debug…

Linux——Ubuntu的基础操作

压缩与解压缩 gzip压缩工具 创建文件 a.c和b.c touch a.c touch b.c 压缩文件a.c和b.c gzip a.c gzip b.c 解压缩a.c.gz和b.c.gz gzip -d a.c.gz 对文件夹进行压缩 gzip -r 对文件夹进行解压缩 gzip -rd 注意&#xff1a;这只是对文件夹里所有文件进行压缩&#xff0c…