网站建设联/软文吧

网站建设联,软文吧,web开发不只是做网站,桂林市天气预报15天准确专栏:Java数据结构秘籍 个人主页:手握风云 目录 一、哈希表 1.1. 概念 1.2. 冲突 1.3. 避免冲突 1.4. 解决冲突 1.5. 实现 二、OJ练习 2.1. 只出现一次的数字 2.2. 随机链表的复制 2.3. 宝石与石头 一、哈希表 1.1. 概念 顺序结构以及平衡树中…

专栏:Java数据结构秘籍

个人主页:手握风云

目录

一、哈希表

1.1. 概念

1.2. 冲突

1.3. 避免冲突

1.4. 解决冲突

1.5. 实现

二、OJ练习

2.1. 只出现一次的数字

2.2. 随机链表的复制

 2.3. 宝石与石头


一、哈希表

1.1. 概念

        顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找⼀个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(n),平衡树中为树的⾼度,即O(n),搜索的效率取决于搜索过程中元素的比较次数。

        理想的搜索⽅法:可以不经过任何比较,⼀次直接从表中得到要搜索的元素。如果构造⼀种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。

        当向该结构中,根据待插⼊元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放;对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功。该方式即为哈希(散列)方法,哈希方法中使⽤的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)。

        哈希函数设置为:hash(key) = key % capacity;其中capacity为存储元素底层空间总的大小。

        我们设一个整数集合{1,7,6,4,5,9},把capacity设置为10,那我们就可以按照下图来存储。如果我们再想存放一个元素12,我们可以直接通过哈希函数存进下标2中,要想搜索,直接通过2下标来找到12,这样时间复杂度为O(n),从而提高效率。

1.2. 冲突

        不同关键字通过相同哈希函数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。把具有不同关键码⽽具有相同哈希地址的数据元素称为“同义词”。例如我们要想存放一个14,通过上面的哈希函数应该存到4下标,但此时4下标已经存了一个4,就会造成哈希冲突。

        出现了哈希冲突,我们就要想办法避免冲突。由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,就会导致冲突的发⽣是必然的,但我们能做的应该是尽量的降低冲突率。

1.3. 避免冲突

        第一种方法可以设计合理的哈希函数。设计原则:定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间;计算出来的地址能均匀分布在整个空间中;比较简单。

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

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

        哈希函数设计的越精妙,产生哈希冲突的可能性就越低,但是无法避免哈希冲突。

        我们还有另外一种就是调节负载因子。哈希表的载荷因子为:ą=填入表中元素个数/哈希表长度。当冲突率达到⼀个⽆法忍受的程度时,我们需要通过降低负载因子来变相的降低冲突率。已知哈希表中已有的关键字个数是不可变的,那我们能调整的就只有哈希表中的数组的大小。

1.4. 解决冲突

        解决哈希冲突两种常⻅的⽅法是:闭散列和开散列。

        闭散列:也叫开放地址法,当发⽣哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下⼀个” 空位置中去。那如何寻找下⼀个空位置呢?此时我们就需要应用线性探索。从发生冲突的位置开始,依次向后探测,直到寻找到下⼀个空位置为止。但这样还是会有一个缺点,就是会使得冲突元素聚集在一起,并且如果我们把4删除了,又如何寻找14、24、34这些元素。因此线性探测采⽤标记的伪删除法来删除⼀个元素。

        ⼆次探测为了避免该问题,找下⼀个空位置的⽅法为:Hi = (H0+i^2)%m,i表示冲突的次数,m为表的大小。

        开散列:开散列法⼜叫链地址法(开链法),⾸先对关键码集合⽤散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每⼀个⼦集合称为⼀个桶,各个桶中的元素通过⼀个单链表链接起来,各链表的头结点存储在哈希表中。

1.5. 实现

        由于我们需要节点数组来创建哈希表,利用内部类来表示节点对象。

public class HashBucket {//创建节点数组static class Node{public int key;public int val;public Node next;public Node(int key, int val) {this.key = key;this.val = val;}}public Node[] array = new Node[10];public int UsedSize;//表示还系统中存放的元素public static final float LOAD_FACTOR = 0.75f;//负载因子表示为常数
}

        我们先来模拟哈希表中放元素的方法。我们要想把元素放入,首先得是一个结点。比如key=14,如果表中已经有14了,就不能再放14并且更新val,所以我们首先需要遍历数组判断key是否相同,如果相同,更新val。下面再使用头插法来把节点元素放入哈希表中。插入元素之后,我们还需要重新计算负载因子是否超过了我们规定的LOAD_FACTOR。如果超过了,就需要进行扩容操作。扩容的时候还需要注意,比如我们要插入的元素的key为14,扩容前需要插入下标为4的位置,扩容2倍后,就需要插入下标为14的位置。

        完整代码实现:

    public void put(int key, int val) {int index = key % array.length;//先遍历index数组下的链表,如果有相同的key,则更新valNode cur = array[index];while (cur != null) {if (cur.key == key) {cur.val = val;return;}cur = cur.next;}//头插法Node node = new Node(key, val);node.next = array[index];array[index] = node;UsedSize++;//重新计算负载因子是不是超过了我们规定的值if (CalculateLoadFactor() >= LOAD_FACTOR) {//扩容ReSize();}}private float CalculateLoadFactor() {return UsedSize * 1.0f / array.length;}private void ReSize() {Node[] newArray = new Node[array.length*2];for (Node node : array) {Node cur = node;while (cur != null) {int newIndex = cur.key % newArray.length;//把当前节点放入新数组的位置,再次使用头插法Node curNext = cur.next;cur.next = newArray[newIndex];newArray[newIndex] = cur;cur = curNext;}}array = newArray;}

        get方法也是一样,也是通过索引下标来寻找目标值。

    public int get(int key){int index = key % array.length;Node cur = array[index];while(cur != null){if(cur.key == key){return cur.val;}cur = cur.next;}return -1;}

        我们在Test类里面进行实例化并调试。

public class Test {public static void main(String[] args) {HashBucket hashBucket = new HashBucket();hashBucket.put(11,99);hashBucket.put(2,99);hashBucket.put(43,99);hashBucket.put(4,99);hashBucket.put(14,99);hashBucket.put(24,99);hashBucket.put(7,99);hashBucket.put(8,99);}
}

        我们上面的方法key是整型,那如果key是引用类型呢,比如String或者Person类。那我们就把整型换作是泛型K、V。需要注意的是,key换成了泛型,不能直接进行%操作,我们可以使用hashCode方法转成整型,并且进行比较要使用equals方法。

/*** @author: gao* @create-date: 2025/3/15 16:32*/public class HashBucket<K, V> {static class Node<K, V> {public K key;public V val;public Node<K, V> next;public Node(K key, V val) {this.key = key;this.val = val;}}public Node<K, V>[] array = (Node<K, V>[]) new Node[10];public int UsedSize;//表示还系统中存放的元素public static final float LOAD_FACTOR = 0.75f;//负载因子表示为常数public void put(K key, V val) {int hashcode = key.hashCode();int index = hashcode % array.length;//先遍历index数组下的链表,如果有相同的key,则更新valNode<K, V> cur = array[index];while (cur != null) {if (cur.key == key) {cur.val = val;return;}cur = cur.next;}Node<K, V> node = new Node<K, V>(key, val);node.next = array[index];array[index] = node;UsedSize++;}public V get(K key) {int hashcode = key.hashCode();int index = hashcode % array.length;Node<K, V> cur = array[index];while (cur != null) {if (cur.key.equals(key)) {return cur.val;}cur = cur.next;}return null;}
}

        如果我们要判断是否为同一个人,我们可以判断身份证号码是否相等。如果我们按照这种方法去写,发现比较结果为false。这是因为我们没有重写equals和hashCode方法,编译器默认调用Object方法。

class Person {public String id;public Person(String id) {this.id = id;}
}public class Test {public static void main(String[] args) {Person person1 = new Person("1234");Person person2 = new Person("1234");System.out.println(person1.equals(person2));System.out.println(person1.hashCode());System.out.println(person2.hashCode());}
}

    public boolean equals(Object obj) {return (this == obj);}

        我们在Person类里面右击,点击Generate,再点击equals() and hashCode(),就可以重写。

    @Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return Objects.equals(id, person.id);}@Overridepublic int hashCode() {return Objects.hash(id);}

二、OJ练习

2.1. 只出现一次的数字

        我们的基本思路是:利用HashSet,先遍历一遍数组,把集合中没有的数字放入,如果有,再移除,最后集合中剩下的元素就是只出现一次的数字,再遍历一遍数组,匹配HashSet中的数组。

        完整代码实现:

class Solution {public int singleNumber(int[] nums) {Set<Integer> set = new HashSet<>();for (int i = 0;i < nums.length;i++) {if(! set.contains(nums[i])){set.add(nums[i]);}else{set.remove(nums[i]);}}for (int i = 0;i < nums.length;i++) {if(set.contains(nums[i])){return nums[i];}}return -1;}
}

        执行时间还是比较高,因为使用了两次for循环遍历数组。

2.2. 随机链表的复制

        题目比较长,大概题意就是复制出一份与原来相同的链表。这道题的难点在于比单链表多了一个可以指向任意节点或者空的random域。起初,很多人会去想定义一个Node cur去遍历一遍链表,一个一个节点进行拷贝,但一拷贝就会发现问题,因为我们我们不知道cur.next和cur.random是哪一个节点的地址。既然遍历一遍链表不行,那就遍历两遍。第一遍遍历,所有节点的val域全都拷贝过来,next域以及random域全都默认为null,每遍历一个链表,就新实例化一个节点。然后我们<K,V>结构来建立老节点与新节点之间的映射关系。

        我们每获取一个节点的地址,都可以修改它的next域与random域。

        完整代码实现:

class Solution {public Node copyRandomList(Node head) {Map<Node,Node> map = new HashMap<>();//第一遍遍历链表Node cur = head;while(cur != null){Node node = new Node(cur.val);map.put(cur,node);cur = cur.next;}//第二遍遍历链表cur = head;while(cur != null){map.get(cur).next = map.get(cur.next);map.get(cur).random = map.get(cur.random);cur = cur.next;}return map.get(head);}
}

 2.3. 宝石与石头

        题目很简单,就是查找stones中含有jewels中的字符的个数。我们先遍历jewels字符串,将里面的字符放入集合中,再去遍历stones中的字符,最后返回宝石个数。

        完整代码实现:

class Solution {public int numJewelsInStones(String jewels, String stones) {Set<Character> set = new HashSet<>();for (int i = 0; i < jewels.length(); i++) {char ch = jewels.charAt(i);set.add(ch);}int count = 0;for (int i = 0; i < stones.length(); i++) {char ch = stones.charAt(i);if(set.contains(ch)){count++;}}return count;}
}

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

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

相关文章

OpenHarmony子系统开发 - Rust编译构建指导

OpenHarmony子系统开发 - Rust编译构建指导 一、Rust模块配置规则和指导 概述 Rust是一门静态强类型语言&#xff0c;具有更安全的内存管理、更好的运行性能、原生支持多线程开发等优势。Rust官方也使用Cargo工具来专门为Rust代码创建工程和构建编译。 OpenHarmony为了集成C…

STM32驱动代码规范化编写指南(嵌入式C语言方向)

点击下面图片&#xff0c;为您提供全新的嵌入式学习路线 文章目录 一、命名规范体系1.1 变量/函数命名1.2 宏定义规范1.3 类型定义 二、代码结构组织2.1 文件组织结构2.2 头文件规范模板 三、注释体系构建3.1 Doxygen风格示例3.2 复杂逻辑注释 四、硬件抽象层设计4.1 寄存器封…

Trae与Builder模式初体验

说明 下载的国际版&#xff1a;https://www.trae.ai/ 建议 要选新模型 效果 还是挺不错的&#xff0c;遇到问题反馈一下&#xff0c;AI就帮忙解决了&#xff0c;真是动动嘴&#xff08;打打字就行了&#xff09;&#xff0c;做些小的原型效果或演示Demo很方便呀&#xff…

【设计模式】《设计模式:可复用面向对象软件的基础》:设计模式怎样解决设计问题?

文章目录 ⭐前言⭐一、设计模式怎样解决设计问题&#xff1f;&#x1f31f;1、寻找合适的对象&#x1f31f;2、决定对象的粒度&#x1f31f;3、指定对象接口&#x1f31f;4、描述对象的实现&#x1f31f;5、运用复用机制✨(1)针对接口编程&#xff0c;而不是针对实现编程。✨(2…

【项目管理git】git学习

ps&#xff1a;所有东西都是个人理解 文章目录 一、git是什么&#xff0c;它用来做什么&#xff1f;二、相关知识库2.1 简单的linux指令2.2 git配置指令2.3 git常见的指令2.3.1 Git的上传原理2.3.2 版本回退相关内容 2.4 设置远程地址&#xff0c;本地上传到github2.4.1 ssh相…

python速通小笔记-------1.容器

1.字符串的标识 字符串需要用“”标识。 与c不同&#xff0c;python 写变量时 不需要标明数据类型每一行最后不需要加&#xff1b; 2.print函数的使用 与c中的printf函数一致 3.运算符 4.字符串str操作 1. 实现字符串拼接 2.% 实现字符串初始化 %s占位会把变量强制转变为…

零基础上手Python数据分析 (2):Python核心语法快速入门

写在前面 场景:每周销售数据报表整理 任务描述: 你需要每周从多个Excel文件中汇总销售数据,计算各项指标(销售额、订单量、客单价等),并生成周报。Excel操作痛点: 文件太多,手动打开复制粘贴,效率低下,容易出错。 多个Excel文件,每个都要打开、筛选、复制数据,重复…

【PHP】获取PHP-FPM的状态信息

文章目录 一、前言二、环境三、过程1&#xff09;修改PHP-FPM配置文件2&#xff09;修改Nginx配置文件3&#xff09;访问页面4&#xff09;修改状态页面端口 一、前言 PHP-FPM内置有一个状态页面&#xff0c;通过这个页面可以获取到FPM的一些状态信息&#xff08;见下图&#…

搭建Spring Boot Admin监控系统

什么是Spring Boot Admin Spring Boot Admin 是一个用于管理和监控 Spring Boot 应用程序的开源工具。它提供了一个用户友好的 Web 界面&#xff0c;用于集中管理和监控多个 Spring Boot 应用程序的运行状态、健康状况、日志、配置等信息。 Spring Boot Admin 的核心功能 应用…

[CISCN 2022 初赛]ezpop(没成功复现)

打开在线环境可以看到&#xff1a; 记得之前做过一个类似的就是有点像照着漏洞去复现。应该可以直接在网上找到链子去打。 www.zip查看路由是 Index/test&#xff0c;然后 post 传参 a&#xff1a; exp&#xff08;参考了别的大神的wp&#xff09;&#xff1a; <?php //…

C 语 言 --- 二 维 数 组 的 应 用

C 语 言 --- 二 维 数 组 的 应 用 第 一 题 - - - 冒 泡 排 序冒 泡 排 序冒 泡 排 序 的 原 理 第 二 题 - - - 回 型 矩 阵特 点 第 三 题 - - - 蛇 形 矩 阵总结 &#x1f4bb;作者简介&#xff1a;曾 与 你 一 样 迷 茫&#xff0c;现 以 经 验 助 你 入 门 C 语 言 &…

5G核心网实训室搭建方案:轻量化部署与虚拟化实践

5G核心网实训室 随着5G技术的广泛应用&#xff0c;行业对于5G核心网人才的需求日益增长。高校、科研机构和企业纷纷建立5G实训室&#xff0c;以促进人才培养、技术创新和行业应用研究。IPLOOK凭借其在5G核心网领域的深厚积累&#xff0c;提供了一套高效、灵活的5G实训室搭建方…

寄生虫仿生算法:基于寄生虫特征的算法设计

寄生虫仿生算法:基于寄生虫特征的算法设计 基于寄生虫行为特征的仿生算法设计 import random import numpy as npclass EnhancedPBOA:def __init__(self, host_env, max_generations, population_size50):self.host_env host_envself.max_generations max_generationsself.p…

【医学影像 AI】基于深度学习的 ROP 病变检测图像评估系统

【医学影像 AI】基于深度学习的 ROP 病变检测图像评估系统 0. 论文简介0.1 基本信息0.2 摘要 1. 引言2. 材料与方法2.1 研究人群2.2 疾病分类与参考标准的制定2.3 深度学习系统开发2.4 定量严重程度评分2.5 数据分析 3. 结果4. 讨论6. 参考文献 0. 论文简介 0.1 基本信息 201…

Cursor初体验:excel转成CANoe的vsysvar文件

今天公司大佬先锋们给培训了cursor的使用&#xff0c;还给注册了官方账号&#xff01;跃跃欲试&#xff0c;但是测试任务好重&#xff0c;结合第三方工具开发也是没有头绪。 但巧的是&#xff0c;刚好下午有同事有个需求&#xff0c;想要把一个几千行的excel转成canoe的系统变…

每日一题---单词搜索(深搜)

单词搜索 给出一个二维字符数组和一个单词&#xff0c;判断单词是否在数组中出现&#xff0c; 单词由相邻单元格的字母连接而成&#xff0c;相邻单元指的是上下左右相邻。同一单元格的字母不能多次使用。 数据范围&#xff1a; 0 < 行长度 < 100 0 < 列长度 <…

【深度学习】多源物料融合算法(一):量纲对齐常见方法

目录 一、引言 二、量纲对齐常见方法 2.1 Z-score标准化Sigmoid归一化 2.2 Min-Max 归一化 2.3 Rank Transformation 2.4 Log Transformation 2.5 Robust Scaling 3、总结 一、引言 类似抖音、快手、小红书等产品的信息流推荐业务&#xff0c;主要通过信息流广告、信…

用C++新建快捷方式

1.创建文件 新建一个文件Ink.cpp,系统会自动生成对应的EXE文件 2.编写代码 #include<stdlib.h> int main(){ system("powershell -command \"$WshShellNew-Object -comObject WScript.Shell; $Shortcut$WshShell.CreateShortcut(\%UserProfile%\\Desktop\\1.…

基于Python的天气预报数据可视化分析系统-Flask+html

开发语言&#xff1a;Python框架&#xff1a;flaskPython版本&#xff1a;python3.8数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 系统登录 可视化界面 天气地图 天气分析 历史天气 用户管理 摘要 本文介绍了基于大数据…

基于Uniapp开发tab选项卡/标签栏前端组件

在开发一些业务场景时候&#xff0c;可能需要切换标签栏来展示不同的信息列表。 为此开发了一个Uniapp组件&#xff08;myTab&#xff09;&#xff0c;下面为组件的展示效果&#xff1a; 案例代码&#xff1a; <template><view class"content"><myt…