【数据结构】Java中Map和Set详解(含二叉搜索树和哈希表)

目录

Map和Set详解 

 1.二叉搜索树

2.Map常见方法

3.Set常见方法

4.哈希表


Map和Set详解 

Map:一种键值对结构,hashMap中键和值均可以为空,hashTable中则不可以存放null值

Set:一种集合,不能存放重复元素,可以理解为与map中的键的集合。

Map set 是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关

在Java中Map和Set最常见到下面四个实现类,HashMap/TreeMap/HashSet/TreeSet,他们分别与两种数据结构相关,二叉搜索树和哈希表,下面的文章中我会详解这两种数据结构,以及Java是怎样对这两种数据结构进行实现的。

 1.二叉搜索树

     二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
  • 若它的左子树不为空,则左子树上所有节点都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

如下图所示:

二叉搜索树的模拟实现:
public class BinarySearchTree {public static class Node {int key;Node left;Node right;public Node(int key) {this.key = key;}}private Node root = null;/*** 在搜索树中查找 key,如果找到,返回 key 所在的结点,否则返回 null* @param key* @return*/public Node search(int key) {Node cur = root;while (cur != null) {if (key == cur.key) {return cur;} else if (key < cur.key) {cur = cur.left;} else {cur = cur.right;}}return null;}/*** 插入* @param key* @return true 表示插入成功, false 表示插入失败*/public boolean insert(int key) {if (root == null) {root = new Node(key);return true;}Node cur = root;Node parent = null;while (cur != null) {if (key == cur.key) {return false;} else if (key < cur.key) {parent = cur;cur = cur.left;} else {parent = cur;cur = cur.right;}}Node node = new Node(key);if (key < parent.key) {parent.left = node;} else {parent.right = node;}return true;}/*** 删除成功返回 true,失败返回 false* @param key* @return*/public boolean remove(int key) {return delete(root,key);}private boolean delete(Node root,int key){/*
根据cur的孩子是否存在分四种情况
1. cur左右孩子均不存在
2. cur只有左孩子
3. cur只有右孩子
4. cur左右孩子均存在
看起来有四种情况,实际情况1可以与情况2或者3进行合并,只需要处理是那种情况即可
除了情况4之外,其他情况可以直接删除
情况4不能直接删除,需要在其子树中找一个替代节点进行删除
*/Node cur = root;Node parent = null;while (cur != null) {if (key == cur.key) {break;} else if (key < cur.key) {parent = cur;cur = cur.left;} else {parent = cur;cur = cur.right;}}
// 该元素不在二叉搜索树中if(null == cur){return false;}
//由于二叉查找树的性质,如果将当前节点替换为左子树中最大的或者右子树中最小的一定不会破坏二叉查找树的结构。if((cur.left!=null&&cur.right==null)||(cur.left==null&&cur.right==null)){cur=cur.left;}else if(cur.left==null&&cur.right!=null){cur=cur.right;}else{int val=SearchleftMax(cur.left);cur.key=val;delete(cur.left,val);}return true;}private int SearchleftMax(Node left) {if(left==null){return 0;}if(left.right==null){return left.key;}return SearchleftMax(left.right);}}

 性能分析:       

二叉搜索树的插入和删除操作都离不开查找,所以主要看二叉搜索树的查找效率。
二叉搜索树的查找效率与树的高度有关,结点越深,所需要的比较次数越多。对于同一个数的集合来说,关键码的插入次序不同也会得到不同结构的二叉搜索树。
  1. 最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:log2N
  2. 最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2

可以看到如果退化为单支树,性能就会下降非常多。为了保证二叉搜索树的效率,大佬们还发明AVL树和红黑树,来限制树的高度尽量趋近于完全二叉树。

TreeMap TreeSet java 中利用搜索树实现的 Map Set ;实际上用的是红黑树,而红黑树是一棵近似平衡的二叉搜索树,即在二叉搜索树的基础之上 + 颜色以及红黑树性质验证,关于红黑树的内容后序再进行讲解。

                                              

2.Map常见方法

在Java中Map和Set是两个接口,我们可以利用他们选择任意一个实现类。

 map的常见方法:

Map.Entry<K, V> Map 内部实现的用来存放 <key, value> 键值对映射关系的内部类 ,该内部类中主要提供了<key, value>的获取, value 的设置以及 Key 的比较方式。
方法解释
V get (Object key)
返回 key 对应的 value
V getOrDefault (Object key, V defaultValue)
返回 key 对应的 value key 不存在,返回默认值
V put (K key, V value)
设置 key 对应的 value
V remove (Object key)
删除 key 对应的映射关系
Set<K> keySet ()
返回所有 key 的不重复集合
Collection<V> values ()
返回所有 value 的可重复集合
Set<Map.Entry<K, V>> entrySet ()
返回所有的 key-value 映射关系
boolean containsKey (Object key)
判断是否包含 key
boolean containsValue (Object value)
判断是否包含value

  1. Map是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap
  2. Map中存放键值对的Key是唯一的,value是可以重复的
  3. TreeMap中插入键值对时,key不能为空,否则就会抛NullPointerException异常value可以为空。但是HashMapkeyvalue都可以为空。
  4. Map中的Key可以全部分离出来,存储到Set来进行访问(因为Key不能重复)
  5. Map中的value可以全部分离出来,存储在Collection的任何一个子集合中(value可能有重复)
  6. Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行重新插入。

3.Set常见方法

Set Map 主要的不同有两点: Set 是继承自 Collection 的接口类, Set 中只存储了 Key
方法解释
boolean add (E e)
添加元素,但重复元素不会被添加成功
void clear ()
清空集合
boolean contains (Object o)
判断 o 是否在集合中
Iterator<E> iterator ()
返回迭代器
boolean remove (Object o)
删除集合中的 o
int size()
返回 set 中元素的个数
boolean isEmpty()
检测 set 是否为空,空返回 true ,否则返回 false
Object[] toArray()
set 中的元素转换为数组返回
boolean containsAll(Collection<?> c)
集合 c 中的元素是否在 set 中全部存在,是返回 true ,否则返回
false
boolean addAll(Collection<? extends
E> c)
将集合 c 中的元素添加到 set 中,可以达到去重的效果
  1. Set是继承自Collection的一个接口类
  2. Set中只存储了key,并且要求key一定要唯一
  3. TreeSet的底层是使用Map来实现的,其使用keyObject的一个默认对象作为键值对插入到Map中的
  4. Set最大的功能就是对集合中的元素进行去重
  5. 实现Set接口的常用类有TreeSetHashSet,还有一个LinkedHashSetLinkedHashSet是在HashSet的基础上维护了一个双向链表来记录元素的插入次序。
  6. Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入
  7. TreeSet中不能插入nullkeyHashSet可以。

4.哈希表

顺序结构以及平衡树 中,元素关键码与其存储位置之间没有对应的关系,因此在 查找一个元素时,必须要经过关键 码的多次比较 顺序查找时间复杂度为 O(N) ,平衡树中为树的高度,即 O(log2N ) ,搜索的效率取决于搜索过程中元素的比较次数。
理想的搜索方法:可以 不经过任何比较,一次直接从表中得到要搜索的元素 如果构造一种存储结构,通过某种函 (hashFunc) 使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快 找到该元素
当向该结构中:
  • 插入元素 根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
  • 搜索元素 对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功
该方式即为哈希 ( 散列 ) 方法, 哈希方法中使用的转换函数称为哈希 ( 散列 ) 函数,构造出来的结构称为哈希表 (Hash Table)( 或者称散列表 )
例如:数据集合 {1 7 6 4 5 9}
哈希函数设置为: hash(key) = key % capacity ; capacity 为存储元素底层空间总的大小。

 冲突的诞生:

对于两个数据元素的关键字ki 和kj (i != j) ,有  i != j  ,但有: Hash(ki) == Hash(kj) ,即: 不同关键字通过相同哈 希函数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞

关于如何解决哈希冲突我将会在下篇文章进行分享,欢迎大家关注我的博客在文章发布的第一时间来捧场呀!!!

主页已更新完Java基础内容,数据结构基础,

正在更新算法篇,数据库篇,

未来会更新Java项目,SpringBoot,Redis以及各种Java路线会用到的技术。

求点赞!求收藏!求评论!求关注!

谢谢大家!!!!!!!!!

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

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

相关文章

第一篇:概述、 目录、适用范围及术语 --- IAB/MRC《增强现实(AR)广告(效果)测量指南1.0 》

第一篇&#xff1a;概述、目录、适用范围及术语 - IAB与MRC及《增强现实广告效果测量指南1.0》 --- 我为什么要翻译美国IAB科技公司系列标准 ​​​​​​​​​​​​​​ 翻译计划 第一篇概述—IAB与MRC及《增强现实广告效果测量指南》之目录、适用范围及术语第二篇广告效…

【C语言】——指针四:字符指针与函数指针变量

【C语言】——指针四&#xff1a;字符指针与函数指针变量 一、字符指针二、函数指针变量2.1、 函数指针变量的创建2.2、两段有趣的代码 三、typedef关键字3.1、typedef的使用3.2、typedef与define比较 四、函数指针数组 一、字符指针 在前面的学习中&#xff0c;我们知道有一种…

【技术栈】Redis 中的事务及持久化方式

SueWakeup 个人主页&#xff1a; SueWakeup 系列专栏&#xff1a;学习技术栈 个性签名&#xff1a;保留赤子之心也许是种幸运吧 本文封面由 凯楠&#x1f4f8; 友情提供 目录 相关传送门 1. Redis 中的事务 2. Redis 持久化 2.1 RDB 方式 2.1.1 RDB手动 2.1.2 RDB自动 2.…

线性表的合并之求解一般集合的并集问题(单链表)

目录 1问题描述&#xff1a; 2问题分析&#xff1a; 3代码如下&#xff1a; 4运行结果&#xff1a; 1问题描述&#xff1a; 已知两个集合A和B&#xff0c;现要求一个新的集合AAuB。例如&#xff0c;设 A&#xff08;7&#xff0c;5&#xff0c;3&#xff0c;11&#xff09;…

哲学♂家带你用动态内存函数实现二维数组

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、思路分析 二、实现 总结 前言 最近在做题的时候发现一个比较考验技术的问题&#xff0c;用内存函数模拟实现二维数组&#xff0c;接下来给大家演示一下我的做…

Java进阶—GC回收(垃圾回收)

1. 什么是垃圾回收 垃圾回收(Garbage Collection&#xff0c;GC)是Java虚拟机(JVM)的一项重要功能&#xff0c;用于自动管理程序中不再使用的内存。在Java中&#xff0c;程序员不需要手动释放内存&#xff0c;因为GC会自动检测并回收不再使用的对象&#xff0c;从而减少内存泄…

arm作业3

key_inc.c #include"key_inc.h"void key1_it_config(){//使能GPIOF外设时钟RCC->MP_AHB4ENSETR | (0x1<<5);//将PF9设置为输入模式GPIOF->MODER & (~(0x3<<18));//设置由PF9管脚产生EXTI9事件EXTI->EXTICR3 & (~(0XFF<<8));EXTI-…

图解Kafka架构学习笔记(三)

准备Kafka环境 这里推荐使用Docker Compose快速搭建一套本地开发环境。 以下docker-compose.yml文件用来搭建一套单节点zookeeper和单节点kafka环境&#xff0c;并且在8080端口提供kafka-ui管理界面。 version: 2.1services:zoo1:image: confluentinc/cp-zookeeper:7.3.2hos…

详解:JS异步解决方案之回调函数,及其弊端

「异步编程」是前端工程师日常开发中经常会用到的技术&#xff0c;异步的实现有好几种方式&#xff0c;各有利弊&#xff0c;本篇先讲通过回调来实现来异步 。 一、同步和异步 同步编程和异步编程是两种不同的编程方式。 同步编程是指按照代码的顺序执行&#xff0c;每一行代…

[服务器] 安装Nacos2.2.0-Windows

文章目录 Nacos安装官网下载地址官方个人百度云 单机启动修改端口 登录后台与修改配置浏览器打开管理界面修改默认密码创建配置 Nacos 安装 官网 https://nacos.io/ 下载地址 官方 https://github.com/alibaba/nacos/releases 个人百度云 链接&#xff1a;https://pan.…

javaSSM游泳馆日常管理系统IDEA开发mysql数据库web结构计算机java编程maven项目

一、源码特点 IDEA开发SSM游泳馆日常管理系统是一套完善的完整企业内部系统&#xff0c;结合SSM框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;MAVEN方式加载&#xff0c;系统具有完整的源代码和…

virtualbox导入vdi

新建虚拟机 点击新建 输入新建属性 配置cpu和内存 虚拟硬盘 这里选择已有的vdi文件 摘要 这里点击完成 虚拟机添加成功 点击启动,启动虚拟机 注意 这个时候的ip,还是以前镜像的ip,如果两个镜像一起启动