set,map(java)

前言:要了解set和map,首先需要对搜索树和哈希有一定的了解,才能进一步深入的了解set和map。

1.搜索树

(1)性质:

若它的左子树不为空,则左子树上所有节点值都小于根节点的值。

若它的右子树不为空,则右子树上所有节点值都大于根节点的值。

它的左右子树也分别为二叉搜索树。

二叉搜索树中不允许出现相同的值

eg:

(2)相关功能的实现:

前提得实现一个节点类TreeNode,包含left(左子树),right(右子树),val三个属性。

a.查找:

分析:

时间复杂度:

最好情况:O(\log_{2}N)

最坏情况:O(N) 

代码实现:

public TreeNode search(int val) {if(root == null) {return null;}TreeNode cur = root;while(cur != null) {if (cur.val > val) {//进到左边cur = cur.left;} else if (cur.val < val) {//进到右边cur = cur.right;} else {return cur;}}return null;
}

b.插入:

分析:

时间复杂度与查找的相同。

代码实现:

public void insert(int val) {if(root == null) {root = new TreeNode(val);return;}TreeNode node = new TreeNode(val);TreeNode cur = root;TreeNode parent = null;while(cur != null) {parent = cur;if (cur.val > node.val) {//进到左边cur = cur.left;} else if (cur.val < node.val) {//进到右边cur = cur.right;} else {return;}}//记录父亲节点的用处if(parent.val > node.val) {parent.left = node;}if(parent.val < node.val) {parent.right = node;}
}

c.删除:

分析:

时间复杂度与查找和插入相同。

代码实现:

public void delete(int val) {if(root == null) {return;}TreeNode cur = root;TreeNode parent = null;while(cur != null) {cur = parent;if (cur.val > val) {//进到左边cur = cur.left;} else if (cur.val < val) {//进到右边cur = cur.right;} else {removeNode(parent,cur);}}
}
private void removeNode(TreeNode parent, TreeNode cur) {if(cur.left == null) {if(cur == root) {cur = cur.right;}else if(parent.right == cur) {parent.right = cur.right;}else if(parent.left == cur) {parent.left = cur.right;}}else if(cur.right == null) {if(cur == root) {cur = cur.left;}else if(parent.right == cur) {parent.right = cur.left;}else if(parent.left == cur) {parent.left = cur.left;}}else {TreeNode tmpParent = cur;TreeNode tmp = cur.right;while(tmp.left != null) {tmpParent = tmp;tmp = tmp.left;}cur.val = tmp.val;if(tmpParent.left == tmp) {tmpParent.left = tmp.right;}if(tmpParent.right == tmp) {tmpParent.right = tmp.right;}}
}

(3)和集合类的关系:

TreeSet和TreeMap即java中运用二叉搜索树实现的Set和Map;但实际上是一颗红黑树,红黑树是一颗近似平衡的二叉搜索树(不会出现一些单只树的情况)。

2.哈希表

(1)概念:

通过构造一种存储结构,和某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一 一映射的关系,从而在查找时候能很快速的查找到对应的元素。构造出来的存储结构就成为哈希表,某种转换函数称为哈希函数,上述这中查找方式称为哈希(散列)方法。

eg:

(2)冲突:

a.概念:

不同关键字通过哈希函数计算出相同的哈希地址。

b.避免:

冲突是不能够完全避免的,我们只能设计一个比较合理的哈希函数来尽量降低哈希冲突率

直接定制法:Hash(key) = A * key + B 使用场景:适合查找比较小且连续的情况。

除留余数法:Hash(key) = key % p(p <= m,m为哈希表的长度)

c.负载因子调节(\alpha):

\alpha = 填入表中的元素/哈希表的长度,\alpha越大,表明冲突的概率越大,反之则越小。

d.解决方式:

闭散列:

有线性探测和二次探测两种方式:

线性探测:

线性探测有个缺陷就是冲突的元素易容易堆积在一起。 

二次探测:

研究表明:当表的长度为质数并且负载因子不超过0.5时,新的表项一定能插入,而且任何一个位置都不会被探查两次。因此只要表中有一半的位置,就不存在表满的问题。此时在搜索时可以不考虑装满的情况,但在插入时必须确保表的负载因子不超过0.5,否则需要扩容。

因此闭散列最大的缺陷就是表的利用率比较低。

开散列:(哈希桶,开链法,链地址法)

各个桶中的元素通过一个单链表串起来,各链表头节点存储在哈希表中。

eg:

从上图我们可以看出每个哈希桶中放的都是冲突的元素,此时就可以将开散列认为时是把一个大集合中的搜索问题转化为在小集合中做搜索了。

 3.Map和Set

Set和Map都是java中专门用来搜索的容器/数据结构,其搜索的效率与具体的实列类有关。

以前的搜索方式:直接遍历,二分查找......,这些更适合于静态查找。

而Set和Map更适合于动态查找。

搜索的数据:关键字(key)和关键字对应的称为值(value),它们一起称为key-value键值对。一般有两种模型:纯key模型(Set)和纯key-value模型(Map)。

(1)TreeMap,HashMap:

map是一个接口没有继承于Collection接口,存储的是key-value键值对,key是唯一的,不能重复。

a.使用:

 关于Map.Entry<K,V>的说明:

Entry也是一个接口,只不过是Map内部实现的接口,它是用来存放key-value键值对的映射关系。

主要有三个使用方法:

 Map.Entry<K,V>中没有提供设置key的方法。

b.HashMap源码相关解析:

c.比较:

d.注意:

Map是一个接口,不能够进行实列化对象,要new对象只能通过TreeMap或者HashMap来实现。

Map中key,value的类型可以是所有类型,但TreeMap中的key不能为nul,而HashMap可以

Map中key是唯一的,value不是唯一的。

Map中的key是不能直接进行修改的,Map.Entry中只提供了setValue方法,并为提供setKey方法,所以要想进行修改key,只能删除这个键值对,重新放入元素。

(2)TreeSet,HashSet:

Set是一个接口,继承与Collection接口,Set集合类可以达到天然去重的效果。

a.使用:

b.比较:

c.注意:

Set是一个接口,不能直接实例化对象,只能通过TreeSet或HashSet来new对象。

Set中的元素是唯一的,所以有天然去重的效果。

TreeSet中的值不能为null,HashSet可以。

Set的底层就是有Map来实现的,其使用key与Object一个默认对象作为键值对插入到Map中的。

Set中的key也是不能修改的,要修改只能删除,重新放入。

Set常见实列化的类有TreeSet和HashSet,此外还有LinkedHashSet,其是在HashSet的基础上维护了一个双向链表来记录元素的插入次序。

4.OJ题:

(1)随机链表的复制

分析:

代码实现:

class Solution {public Node copyRandomList(Node head) {HashMap<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)旧键盘

分析:

代码实现:

public static void func(String str1, String str2) {Set<Character> set = new HashSet<>();for (char ch : str2.toUpperCase().toCharArray()) {set.add(ch);}Set<Character> set1 = new HashSet<>();for (char ch : str1.toUpperCase().toCharArray()) {if (!set.contains(ch) && !set1.contains(ch)) {System.out.print(ch);set1.add(ch);}}
}

(3)前k个高频单词

分析:

代码实现:

class Solution {public List<String> topKFrequent(String[] words, int k) {HashMap<String, Integer> map = new HashMap<>();for (String word : words) {if (map.get(word) == null) {map.put(word, 1);} else {int val = map.get(word);map.put(word, val + 1);}}// 建立小根堆PriorityQueue<Map.Entry<String, Integer>> queue = new PriorityQueue<>(new Comparator<Map.Entry<String, Integer>>() {@Overridepublic int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {if (o1.getValue().compareTo(o2.getValue()) == 0) {return o2.getKey().compareTo(o1.getKey());}return o1.getValue().compareTo(o2.getValue());}});for (Map.Entry<String, Integer> entry : map.entrySet()) {if (queue.size() < k) {queue.offer(entry);} else {Map.Entry<String, Integer> tmp = queue.peek();if (tmp.getValue().compareTo(entry.getValue()) < 0) {queue.poll();queue.offer(entry);} else {// 按照字符顺序排if (tmp.getValue().compareTo(entry.getValue()) == 0) {if (tmp.getKey().compareTo(entry.getKey()) > 0) {queue.poll();queue.offer(entry);}}}}}List<String> list = new LinkedList<>();for (int i = 0; i < k; i++) {Map.Entry<String, Integer> tmp = queue.poll();list.add(tmp.getKey());}Collections.reverse(list);return list;}
}

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

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

相关文章

TypeScript学习篇-类型介绍使用、ts相关面试题

文章目录 基础知识基础类型: number, string, boolean, object, array, undefined, void(代表该函数没有返回值)unknownenum(枚举): 定义一个可枚举的对象联合类型: | (联合类型一次只能一种类型&#xff1b;而交叉类型每次都是多个类型的合并类型。)交叉类型: & (联合类型…

按图搜索新体验:阿里巴巴拍立淘API返回值详解

阿里巴巴拍立淘API是一项基于图片搜索的商品搜索服务&#xff0c;它允许用户通过上传商品图片&#xff0c;系统自动识别图片中的商品信息&#xff0c;并返回与之相关的搜索结果。以下是对阿里巴巴拍立淘API返回值的详细解析&#xff1a; 一、主要返回值内容 商品信息 商品列表…

【算法/学习】前缀和差分

前缀和&&差分目录 1. 前缀和的概念及作用 &#x1f308;概念 &#x1f308;用途 &#x1f319;一维前缀和 &#x1f319;二维前缀和 2. 差分的概念及用途 &#x1f308;概念&#xff1a; &#x1f308;用途 &#x1f319;一维差分 &#x1f319;二维差分 1. …

Linux系统编程——线程池

目录 一&#xff0c;池化技术 二&#xff0c;线程池概念 三&#xff0c;线程池实现 3.1 线程封装 3.2 预备头文件实现 3.3 线程池类的简单实现 3.4 主函数实现 3.5 效果展示 一&#xff0c;池化技术 池化技术是计算机编程领域非常常用的一种技术&#xff0c;该技术可以…

【前端/js】使用js读取本地文件(xml、二进制)内容

目录 说在前面FileReaderDOMParser文本文件二进制文件 说在前面 浏览器版本&#xff1a;Microsoft Edge 126.0.2 (正式版本) (64 位) FileReader MDNFileReader 接口允许 Web 应用程序异步读取存储在用户计算机上的文件&#xff08;或原始数据缓冲区&#xff09;的内容&#x…

CL4056D 1A锂离子电池线性充电器芯片IC

一般描述 CL4056D是一款ESOP8封装的独立线性锂离子电池充电器。由于外部元件较少&#xff0c;因此CL4056D非常适合用于各种便携式应用。充电电流可以通过外部电阻器进行编程。在待机模式下&#xff0c;供电电流将降低到约35uA。当输入电压断开时&#xff0c;CL4056 D将进…

UWA Gears正式上线,助力移动平台性能优化

亲爱的开发者朋友们&#xff0c; 我们非常激动地向大家宣布&#xff0c;UWA最新的无SDK性能分析工具 - UWA Gears&#xff0c;现已正式发布&#xff01;无论您使用的是哪种开发引擎&#xff0c;这款工具都能轻松应对&#xff0c;为您的项目保驾护航。更令人心动的是&#xff0c…

Lua编程

文章目录 概述lua数据类型元表注意 闭包表现 实现 lua/c 接口编程skynet中调用层次虚拟栈C闭包注册表userdatalightuserdata 小结 概述 这次是skynet&#xff0c;需要一些lua/c相关的。写一篇博客&#xff0c;记录下。希望有所收获。 lua数据类型 boolean , number , string…

在react中如何计算本地存储体积

1.定义useLocalStorageSize钩子函数 // 计算localStorage大小 function useLocalStorageSize() {const [size, setSize] useState(0);useEffect(() > {const calculateSize () > {let totalSize 0;for (let key in localStorage) {//过滤掉继承自原型链的属性if (loc…

Redis是多线程还是单线程?

文章目录 1、用户态和内核态2、阻塞IO3、非阻塞IO4、IO多路复用4.1 select4.2 poll4.3 epoll4.4 epoll中的ET和LT4.5 epoll的服务端流程 5、信号驱动6、异步IO7、对比8、Redis是单线程的吗&#xff1f;9、单线程多线程网络模型变更 1、用户态和内核态 1、ubuntu和Centos 都是Li…

基于PaddleClas的人物年龄分类项目

目录 一、任务概述 二、算法研发 2.1 下载数据集 2.2 数据集预处理 2.3 安装PaddleClas套件 2.4 算法训练 2.5 静态图导出 2.6 静态图推理 三、小结 一、任务概述 最近遇到个需求&#xff0c;需要将图像中的人物区分为成人和小孩&#xff0c;这是一个典型的二分类问题…

Python | Leetcode Python题解之第283题移动零

题目&#xff1a; 题解&#xff1a; class Solution:def moveZeroes(self, nums: List[int]) -> None:n len(nums)left right 0while right < n:if nums[right] ! 0:nums[left], nums[right] nums[right], nums[left]left 1right 1

ClickHouse 进阶【建表、查询优化】

1、ClickHouse 进阶 因为上一节部署了集群模式&#xff0c;所以需要启动 Zookeeper 和 ck 集群&#xff1b; 1.1、Explain 基本语法 EXPLAIN [AST | SYNTAX | PLAN | PIPELINE] [setting value, ...] SELECT ... [FORMAT ...] AST&#xff1a;用于查看语法树SYNTAX&#…

橙单后端项目下载编译遇到的问题与解决

今天下载orange-admin项目&#xff0c;不过下载下来运行出现一些问题。 1、涉及到XMLStreamException的几个类都出现下面的错误 The package javax.xml.stream is accessible from more than one module: <unnamed>, java.xml ctrl-shift-t 可以找到这个引入是哪些包里…

成为git砖家(5): 理解 HEAD

文章目录 1. git rev-parse 命令2. 什么是 HEAD2.1 创建分支当并未切换&#xff0c; HEAD 不变2.2 切换分支&#xff0c;HEAD 改变2.3 再次切换分支&#xff0c; HEAD 再次改变 3. detached HEAD4. HEAD 表示分支、表示 detached HEAD 有什么区别&#xff1f;区别相同点 5. HEA…

【SpringCloud】企业认证、分布式事务,分布式锁方案落地-2

目录 高并发缓存三问 - 穿透 缓存穿透 概念 现象举例 解决方案 缓存穿透 - 预热架构 缓存穿透 - 布隆过滤器 布隆过滤器 布隆过滤器基本思想​编辑 了解 高并发缓存三问 - 击穿 缓存击穿 高并发缓存三问 - 雪崩 缓存雪崩 解决方案 总结 为什么要使用数据字典&…

Python网络爬虫:基础与实战!附淘宝抢购源码

Python网络爬虫是一个强大的工具&#xff0c;用于从互联网上自动抓取和提取数据。下面我将为你概述Python网络爬虫的基础知识和一些实战技巧。 Python网络爬虫基础 1. HTTP请求与响应 网络爬虫的核心是发送HTTP请求到目标网站并接收响应。Python中的requests库是处理HTTP请求…

Java NIO (一)

因工作需要我接触到了netty框架&#xff0c;这让我想起之前为夺高薪而在CSDN购买的Netty课程。如今看来&#xff0c;这套课程买的很值。这套课程中关于NIO的讲解&#xff0c;让我对Tomcat产生了浓厚的兴趣&#xff0c;于是我阅读了Tomcat中关于服务端和客户端之间连接部分的源码…

乐尚代驾六订单执行一

加载当前订单 需求 无论是司机端&#xff0c;还是乘客端&#xff0c;遇到页面切换&#xff0c;重新登录小程序等&#xff0c;只要回到首页面&#xff0c;查看当前是否有正在执行订单&#xff0c;如果有跳转到当前订单执行页面 之前这个接口已经开发&#xff0c;为了测试&…

JAVAWeb实战(后端篇)

因为前后端代码内容过多&#xff0c;这篇只写后端的代码&#xff0c;前端的在另一篇写 项目实战一&#xff1a; 1.创建数据库,表等数据 创建数据库 create database schedule_system 创建表&#xff0c;并添加内容 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------…