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

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

一,哈希表

什么是哈希表,哈希表是一种非常非常高效的数据结构,它用来搜索我们想要的数据,我们之前学过很多查找方法,最快基本时间复杂度就是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复制一份放到value
            map.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;

        //方法2
        Map<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;
    }
}

 

 

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

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

相关文章

R语言贝叶斯分层、层次(Hierarchical Bayesian)模型房价数据空间分析

原文链接&#xff1a;https://tecdat.cn/?p38077 本文主要探讨了贝叶斯分层模型在分析区域数据方面的应用&#xff0c;以房价数据为例&#xff0c;详细阐述了如何帮助客户利用R进行模型拟合、分析及结果解读&#xff0c;展示了该方法在处理空间相关数据时的灵活性和有效性。&a…

拉取git代码不适用ssh,使用用户名及密码

最近换了新电脑&#xff0c;拉取git代码&#xff0c;提示我需要配置ssh&#xff0c;但是着实是有点麻烦了&#xff0c;所以使用用户名和密码的方式可以直接拉取 首先登陆git后找到对应项目地址&#xff0c;有ssh 和http。但是这两种都不是我们要用的地址&#xff0c;使用用户名…

第三十一章 Vue之路由(VueRouter)

目录 一、引言 1.1. 路由介绍 二、VueRouter 三、VueRouter的使用 3.1. 使用步骤&#xff08;52&#xff09; 3.2. 完整代码 3.2.1. main.js 3.2.2. App.vue 3.2.3. Friend.vue 3.2.4. My.vue 3.2.5. Find.vue 一、引言 1.1. 路由介绍 Vue中路由就是路径和组件的映…

Windows转Mac过渡指南

最近由于工作原因开始使用mac电脑&#xff0c;说实话刚拿到手的时候&#xff0c;window党表示真的用不惯。坚持用一下午之后&#xff0c;发现真的yyds&#xff0c;这篇文章说说mac电脑的基本入门指南。 1. 不会使用mac的触摸板&#xff0c;接上鼠标发现滚轮和windows是反的。 …

408——计算机网络(持续更新)

文章目录 一、计算机网络概述1.1 计算机网络的概念1.2 计算机网络体系结构1.3 总结 二、物理层2.1 物理层的基本概念2.2 物理层的基本通信技术2.3 总结 一、计算机网络概述 1.1 计算机网络的概念 计算机网络的定义&#xff1a;将地理位置不同的具有独立功能的计算机通过网络线路…

Linux下安装MongoDB

1.版本选择 偶数版本为稳定版&#xff0c;个人为了学习&#xff0c;选择较低版本5.0.30 2.下载 1. 个人使用下载社区版本 2.进入community version中 3.推荐直接使用&#xff1a;推荐用直接下载tgz方式&#xff0c;但是主要为了方便&#xff0c;后续会说一下 个人下载了sev…

无人机避障——路径规划篇(一) JPS跳点搜索算法A*算法对比

JSP 跳点搜索算法与改进 A*算法对比 一、算法概述: 跳点搜索(Jump Point Search,JPS)算法:一种用于路径规划的启发式搜索算法。它主要用于在网格地图(如游戏地图、机器人运动规划地图等)中快速找到从起点到终点的最短路径。该算法在改进 A*算法的基础上进行了优化,通过跳过一…

【热门主题】000027 React:前端框架的强大力量

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

win11安装最新rabbitmq

1、安装Erlang 注意&#xff1a;RabbitMQ需要Erlang支持&#xff0c;所以要先安装Erlang&#xff0c;安装RabbitMQ版本需要与之对应的Erlang版本才行查看对应的RabbitMQ对应的Erlang 版本下载Erlang 2、安装RabbitMQ 下载 RabbitMQ Erlang和RabbitMQ安装过程一直点下一步…

distrobox install in ubuntu 22.04 / 在 ubuntu 22.04 上安装 distrobox (***) OK

要点&#xff1a; 本测试实验&#xff0c;采用的是 podman distrobox 在沙盒 snap 中&#xff0c;安装 distrobox 需要使用 --devmode 开发模式&#xff1b;可以避开 distrobox 的版本检查&#xff1f; distrobox 官方文档显示&#xff0c; Installation https://distrobox.i…

leetcode203. Remove Linked List Elements

给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 Given the head of a linked list and an integer val, remove all the nodes of the linked list that has Node.val val, and return …

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-31

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-31 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-31目录1. Large Language Models for Manufacturing摘要创新点算法模型实验效果&#xff08;包含重要数据与结论&#xff09;推荐…

【AI工作流】FastGPT - 深入解析FastGPT工作流编排:从基础到高级应用的全面指南

文章目录 一、工作流编排概述二、FastGPT的节点类型1. 基础功能插件(1) 文本输出(2) 功能调用(3) 工具(4) 外部调用(5) 其他 2. 系统插件3. 团队插件 三、工作流中的流向结语 在当今快速发展的人工智能领域&#xff0c;工作流编排的能力已成为提升用户体验和应用效率的关键因素…

NVR批量管理软件/平台EasyNVR多个NVR同时管理支持对接阿里云、腾讯云、天翼云、亚马逊S3云存储

随着云计算技术的日益成熟&#xff0c;越来越多的企业开始将其业务迁移到云端&#xff0c;以享受更为灵活、高效且经济的服务模式。在视频监控领域&#xff0c;云存储因其强大的数据处理能力和弹性扩展性&#xff0c;成为视频数据存储的理想选择。NVR批量管理软件/平台EasyNVR&…

光通信——WDM/DWDM/CWDM

一、WDM 波分复用原理&#xff1a;将光纤的低损耗窗口可使用的光谱带宽分割为若干子带宽&#xff0c;然后将待传递的电信号调制到各个子带宽的中心波长光载波上同时传输&#xff0c;是一种能在一根光纤中同时实现多波长信道传输的扩容技术。 WDM复用系统可以分为单向和双向两种…

优化EDM邮件营销,送达率与用户体验双赢

EDM邮件营销需选对平台&#xff0c;优化邮件列表&#xff0c;确保内容优质&#xff0c;进行邮件测试&#xff0c;关注用户反馈调整频率&#xff0c;以保高送达率&#xff0c;提升营销效果。 1. 了解电子邮件送达率的重要性 在开始优化邮件送达率之前&#xff0c;首先需要理解电…

TypeScript起航篇·何为TypeScript?

你好&#xff0c;我是安然无虞。 文章目录 什么是 TypeScriptTypeScript 的特性类型系统TypeScript 是静态类型TypeScript 是弱类型总结: 什么是 TypeScript Hello TypeScript 什么是 TypeScript Typed JavaScript At Any Scale. 添加了类型系统的JavaScript&#xff0c;适用…

鸿蒙系统的优势 不足以及兼容性与未来发展前景分析

2024 年 10 月 22 日&#xff1a;华为正式发布原生鸿蒙操作系统 HarmonyOS next&#xff0c;并正式命名为 HarmonyOS 5&#xff0c;这是鸿蒙系统史上最大的升级&#xff0c;实现了国产操作系统从底层架构到应用生态的全面自主可控。 鸿蒙系统与安卓、iOS 相比&#xff0c;具有…

基于凌鸥LKS32MC037鱼缸用FOC潜水泵控制器

随着老百姓生活水平的提高&#xff0c;室内养殖观赏型鱼类的人越来越多&#xff0c;这就催生了鱼缸内小型潜水泵的市场发展。 早期鱼缸潜水泵都采用的方波驱动的控制器。随着技术的进步和芯片成本的下降&#xff0c;本文介绍的基于无感FOC算法潜水泵控制器已经成熟应用并且大批…

WMV怎么转MP4?五个简单好用的视频格式转换方法!

WMV格式&#xff0c;全称为Windows Media Video&#xff0c;是由微软公司开发的一种视频文件格式。采用先进的视频压缩技术&#xff0c;能够在保持较高视觉质量的同时&#xff0c;显著减小文件体积&#xff0c;经常被用于在网络环境下即时观看或收听高质量的音视频内容。同时&a…