Java数据结构面试题(一)

news2025/1/17 9:05:23

目录

一.ArrayList和LinkedList的区别

二.ArrayList和Vector的区别

三.HashMap的底层实现

四.HashMap和ConcurrentHashMap的区别

五.HashMap和HashTable的区别

六.多线程的情况下使用HashMap呢?

七.HashMap的如何扩容呢?

八.哈希冲突


 

本专栏全是博主自己收集的面试题,仅可参考,不能相信面试官就出这种题目。

 

一.ArrayList和LinkedList的区别

实现,ArrayList 和 LinkedList 都是 Java 中的 List 接口的实现类。

不同点:

  1. 它们的底层实现不同:ArrayList 是基于动态数组的数据结构,而 LinkedList 是基于链表的数据结构。
  2. 随机访问性能不同:ArrayList 优于 LinkedList,因为 ArrayList 可以根据下标以 O(1) 时间复杂度对元素进行随机访问。而 LinkedList 的访问时间复杂度为 O(n),因为它需要遍历整个链表才能找到指定位置的元素。
  3. 插入和删除性能不同:LinkedList 优于 ArrayList,因为 LinkedList 的插入和删除操作时间复杂度为 O(1),而 ArrayList 的时间复杂度为 O(n)。

单独针对ArrayList的解析

         初始化时可以指定初始容量的大小,默认为10,扩容机制:增加当前容量的 50%。

二.ArrayList和Vector的区别

        ArrayList 和 Vector 实现了 List 接口,它们都是动态数组的实现,使用方法也是一样,但是也有不同的地方

  • 线程安全性:Vector 是线程安全的,而 ArrayList 不是。所以在多线程环境下,应该使用 Vector。
  • 性能:由于 Vector 是线程安全的,所以它的性能通常比 ArrayList 差。在单线程环境下,ArrayList 比 Vector 快。
  • 初始容量增长方式:当容量不足时,ArrayList 默认会增加 50% 的容量,而 Vector 会将容量翻倍。这意味着在添加元素时,ArrayList 需要更频繁地进行扩容操作,而 Vector 则更适合于存储大量数据。

三.HashMap的底层实现

        在jdk1.7版本之前,HashMap的底层设计通过数组 + 链表实现的,而jdk1.8版本之后,HashMap 底层是通过数组 + 链表或红黑树实现的。

详细解析:在jdk 8 中,当链表达到阈值8时,会自动转化为红黑树!这个优化的目的是为了在哈希冲突较严重时,仍然能够保持较快的查询性能,因为红黑树的查找、插入和删除操作的时间复杂度为 O(log n),相比于链表的 O(n) 更加高效。

         当红黑树的节点小于等于 6 时,为了节省内存空间会将红黑树退化为链表

四.HashMap和ConcurrentHashMap的区别

        HashMap 是 Java 中常用的一种基于哈希表实现的数据结构,用于存储键值对。它提供了快速的插入、删除和查找操作,适用于需要频繁操作的场景。

       ConcurrentHashMap 是 Java 中线程安全的哈希表实现,专为高并发场景设计。它提供了比 HashMap 更好的并发性能,同时保持了类似的接口和功能。

两者之间的对比:

  1. 线程安全上:HashMap是不安全的,但是 ConcurrentHashMap是安全的。
  2. 键值对上:HashMap是允许存在null键和null值的,但 ConcurrentHashMap不允许
  3. 性能表现上:在单线程环境当中,HashMap性能高,因为HashMap不需要额外的控制开销,而ConcurrentHashMap 在多线程并发访问时通常表现更好,特别是在读多写少的场景下,由于其分段锁设计能够显著减少线程之间的竞争,提高并发度,从而提升性能。
  4. 迭代方面:HashMap 的迭代器是快速失败的(迭代过程中不允许结构发生改变),ConcurrentHashMap 的迭代器是弱一致的(可以发生改变,但是不保证获取最新的修改)
  5. 初始化:HashMap 在初始化时可以指定初始容量和负载因子,用于优化性能;ConcurrentHashMap 也可以初始化时指定初始容量和负载因子,但不需要考虑并发情况下的扩容问题,因为它使用了分段锁来管理并发。

扩展问题:ConcurrentHashMap 为什么不能插入null键值对?

解析:从Java8版本之后就可以插入null键了,最开始不能插入的原因是:

        如果允许键为 null,ConcurrentHashMap 内部的哈希算法可能会将 null 的哈希值映射到某个有效的 Segment 或桶位上,这样会导致无法确定存储位置,或者在其他操作中造成错误。

        如果值为 null,其他线程可能无法准确判断是键不存在还是键对应的值为 null,这会增加实现的复杂性和不确定性。

五.HashMap和HashTable的区别

        HashMap 和 Hashtable 都实现了 Map 接口,都是 Java 中用于存储键值对的数据结构,它们的底层数据结构都是数组加链表的形式。但即使如此也存在几点不同:

解析:为什么HashTable不允许存储null键和值,是因为它的key值进行哈希计算,如果为null的话,无法调用该方法,还是会抛出空指针异常,而值为null的话,HashTable源码会主动抛出异常。

  1. 线程安全:Hashtable 是线程安全的,而 HashMap 是非线程安全的。
  2. 性能:因为 Hashtable 使用了 synchronized 给整个方法添加了锁,所以相比于 HashMap 来说,它的性能不如 HashMap。
  3. 存储:HashMap 允许 key 和 value 为 null,而 Hashtable 不允许存储 null 键和 null 值。

HashMap 允许 key 和 value 为 null 的原因是因为在 HashMap 中对 null 值进行了特殊处理,如果为 null 时会把它赋值为 0。

扩展知识:Hashtable 不推荐使用,即使线程安全,也不推荐使用,因为整个方法添加 synchronized 来实现线程安全的,所以它的性能很差。而推荐的是ConcurrentHashMap,性能高。

六.多线程的情况下使用HashMap呢?

        HashMap是不安全的,可是有些面试官就是搞事情,说我就要用,你就说怎么搞吧!

在多线程的情况下,使用HashMap的方法:

        使用 Collections.synchronizedMap() 包装

Map<K, V> synchronizedMap = Collections.synchronizedMap(new HashMap<>());

缺点:并发的性能很低

七.HashMap的如何扩容呢?

        说起HashMap,我们可以了解一下它的底层原理,由数组+链表组建,而扩容则是扩容数组,当 元素个数 > 容量*负载因子 时,就会进行扩容,而默认的负载因子:0.75,初始容量可以调节,默认是16.

或许面试官会追问:为什么不是满了之后再扩容呢?

答:哈希表不像其他的数据容器,它的内部存储数据是有不一样的。元素都会根据键对象的HashCode()方法得到,然后进行一系列的运算,确定键值对在数组当中的位置。

追问:为什么负载因子是0.75呢?怎么不能是0.8、0.6呢?

答:0.75是空间利用率和性能的一个平衡点,可以保证大多数情况下较高的查找效率和插入效率,过高会增加哈希冲突发生的概率,过低会造成存储的元素过少。

八.哈希冲突

元素在存储的过程当中,是怎么样的一个过程呢?

第一步:得到键的哈希值hash

第二步:确定存储位置,方法:(n - 1) & hash  其中的n是数组的长度

第三步:插入键值对,如果确定的存储位置为空,则直接存储,若不为空,则进行查找该存储位置下的链表或者红黑树是否有对应的键值,若有,则更新,若无,则添加在末尾!

第四步:当前元素数量达到了负载因子乘以数组容量的阈值,进行扩容操作,扩容包括创建一个更大的数组,并重新计算所有键值对的存储位置,然后将它们移到新数组中。

哈希冲突,为什么会有哈希冲突呢?

    原因:不同的键可能有相同的哈希码

解决方法:

  1. 链地址法:也就是数组+链表,链表过长转为红黑树
  2. 开放地址法:发生哈希冲突时,通过一定的探测方法(线性探测、二次探测、双重哈希等)在哈希表中寻找下一个可用的位置。这种方法的优点是不需要额外的存储空间,适用于元素数量较少的情况。缺点是容易产生聚集现象,即某些桶中的元素过多,而其他桶中的元素很少。
  3. 再哈希法(Rehashing):当发生哈希冲突时,使用另一个哈希函数计算出一个新的哈希值,然后将元素插入到对应的桶中。这种方法的优点是简单易懂,适用于元素数量较少的情况。缺点是需要额外的哈希函数,且当哈希函数不够随机时,容易产生聚集现象。

扩展知识:线性探测VS二次探测

线性探测:发生哈希冲突时,线性探测会在哈希表中寻找下一个可用的位置,具体来说,它会检查哈希表中下一个位置是否为空,如果为空,则将元素插入该位置;如果不为空,则继续检查下一个位置,直到找到一个空闲的位置为止。

二次探测:如果初始位置已被占用,则使用二次探测序列计算下一个位置,通过二次探测序列,然后依次检查哈希表中的每个位置,直到找到一个空闲的位置为止。二次探测序列通常是一系列平方数的序列,例如 (1^2, 2^2, 3^2, \ldots)。二次探测序列:[ h_i = (hash + c1 \cdot i + c2 \cdot i^2) \mod m ]

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

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

相关文章

图像练习-识别中圆形锡点 (04)

图片 代码 cv::Mat src cv::imread("light_point.png", cv::IMREAD_COLOR);cv::Mat draw src.clone();cv::Rect rt0(20, 80, src.cols - 30, 190);cv::Rect rt1(20, 480, src.cols - 30, 190);cv::Mat gray;cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);cv::Mat …

RpcChannel的调用过程

目录 1. RPC调用方&#xff08;caller&#xff09;的调用(消费)过程 2.在caller下创建文件&#xff1a;calluserservice.cc 3.在src的include下创建文件&#xff1a;mprpcchannel.h 4.在src下创建mprpcchannel.cc 1. RPC调用方&#xff08;caller&#xff09;的调用(消费)过…

网络爬虫(一)深度优先爬虫与广度优先爬虫

1. 深度优先爬虫&#xff1a;深度优先爬虫是一种以深度为优先的爬虫算法。它从一个起始点开始&#xff0c;先访问一个链接&#xff0c;然后再访问该链接下的链接&#xff0c;一直深入地访问直到无法再继续深入为止。然后回溯到上一个链接&#xff0c;再继续深入访问下一个未被访…

堆结构、堆排序

堆 是完全二叉树&#xff0c;类似这种样式的 而这种有右子节点&#xff0c;没左子节点的就不是完全二叉树 分为大根堆和小根堆 大根堆是二叉树里每一颗子树的父节点都是这颗子树里最大的&#xff0c;即每一棵子树最大值是头节点的值 小根堆相反 把数组中从0开始的一段数人…

记录OSPF配置,建立邻居失败的过程

1.配置完ospf后&#xff0c;在路由表中不出现ospf相关信息 [SW2]ospf [SW2-ospf-1]are [SW2-ospf-1]area 0 [SW2-ospf-1-area-0.0.0.0]net [SW2-ospf-1-area-0.0.0.0]network 0.0.0.0 Jul 4 2024 22:11:58-08:00 SW2 DS/4/DATASYNC_CFGCHANGE:OID 1.3.6.1.4.1.2011.5.25 .1…

艺活网DIY手工制作网站源码 工艺制作教程平台源码,带数据

帝国CMS仿《手艺活》DIY手工制作网源码&#xff0c;仿手艺活自适应手机版模板。 带数据库和图片资源&#xff0c;一共5个G大小&#xff0c;下载需耐心。 92开发 手艺活网DIY手工制作网站源码 创意手工艺品制作教程平台系统帝国h5自适应手机端 是一套展示各种 DIY 小物品精美又…

PhysioLLM 个性化健康洞察:手表可穿戴设备实时数据 + 大模型

个性化健康洞察&#xff1a;可穿戴设备实时数据 大模型 提出背景PhysioLLM 图PhysioLLM 实现数据准备用户模型和洞察生成个性化数据总结和洞察是如何生成的&#xff1f; 解析分析 提出背景 论文&#xff1a;https://arxiv.org/pdf/2406.19283 虽然当前的可穿戴设备伴随应用&…

vue目录说明

vue目录说明 主要目录说明 .vscode - - -vscode工具的配置文件夹 node_modules - - - vue项目的运行依赖文件夹 public - - -资源文件夹&#xff08;浏览器图标&#xff09; src- - -源码文件夹 .gitignore - - -git忽略文件 index.html - - -入口html文件 package.json - - -…

SQL执行慢排查以及优化思路

数据库服务器的优化步骤 当我们遇到数据库调优问题的时候&#xff0c;该如何思考呢&#xff1f;我把思考的流程整理成了下面这张图。 整个流程划分成了观察&#xff08;Show status&#xff09;和行动&#xff08;Action&#xff09;两个部分。字母 S 的部分代表观察&#xf…

项目管理实用表格与应用【项目文件资料分享】

项目管理基础知识 项目管理可分为五大过程组&#xff08;启动、规划、执行、监控、收尾&#xff09;十大知识领域&#xff0c;其中包含49个子过程 项目十大知识领域分为&#xff1a;项目整合管理、项目范围管理、项目进度管理、项目成本管理、项目质量管理、项目资源管理、项目…

使用 iconfont.ttf文件保存多个图标文件,并且像文字一样使用代码绘制出来

先看演示效果 这里的多个图标其实是存储在 iconfont.ttf文件中 这个文件里面的图标对应的编码 显示代码 void CMFCApplication3Dlg::OnBnClickedOk() {// 加载字体文件CString fontPath = _T("C:\\Users\\35497\\Desktop\\test\\MFCApplication3\\font\\iconfont.ttf&qu…

searchForm自适应布局 + 按钮插槽

收起 展开 代码&#xff1a; useResizeObserverHooks.js import { useEffect, useLayoutEffect } from "react";export const useResizeObserver (containerDom, domClass, callback) > {useLayoutEffect(() > {let resizeObserver null;let dom null;if …

8人团队历时半年打造开源版GPT-4o,零延迟演示引爆全网!人人可免费使用!

目录 01 Moshi 02 背后技术揭秘 GPT-4o可能要等到今年秋季才会公开。 然而&#xff0c;由法国8人团队开发的原生多模态Moshi&#xff0c;已经达到了接近GPT-4o的水平&#xff0c;现场演示几乎没有延迟&#xff0c;吸引了大量AI专家的关注。 令人惊讶的是&#xff0c;开源版的…

代码随想录算法训练营第69天:图论7[1]

代码随想录算法训练营第69天&#xff1a;图论7 109. 冗余连接II 卡码网题目链接&#xff08;ACM模式&#xff09;(opens new window) 题目描述 有向树指满足以下条件的有向图。该树只有一个根节点&#xff0c;所有其他节点都是该根节点的后继。该树除了根节点之外的每一个节…

AI大模型:解锁未来职业竞争力的金钥匙

AI元年&#xff1a;大模型的革新力量 随着ChatGPT的震撼登场&#xff0c;2023年被标记为AI元年&#xff0c;大模型以其前所未有的影响力&#xff0c;重塑我们的日常生活和工作方式。从日常的问答对话到复杂的编程辅助&#xff0c;乃至创意图像生成&#xff0c;AI大模型展现出超…

怎么还有人分不清路由器、交换机、光猫、WiFi……你真的都了解吗?

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 讲某个具体技术&#xff0c;说不定你头头是道&#xff0c;但关于路由器、交换机、光猫、WiFi的知识细节&…

AI PC(智能电脑)技术分析

一文看懂AI PC&#xff08;智能电脑&#xff09; 2024年&#xff0c;英特尔、英伟达等芯片巨头革新CPU技术&#xff0c;融入AI算力&#xff0c;为传统PC带来质的飞跃&#xff0c;引领智能计算新时代。 2024年&#xff0c;因此被叫作人工智能电脑&#xff08;AI PC&#xff09;…

我尝试了新的 OpenAI 连接器,真太棒了!

我们上个月发布的新连接器将 Open AI 集成简化为仅需几步操作。我实现了聊天完成 API&#xff08;有和没有上下文&#xff09;&#xff0c;并想编写一个关于其工作原理的快速教程。 先决条件 与往常一样&#xff0c;在进入主要构建之前我们需要做一些准备工作。你会需要&…

FFT 简单基础(matlab

使用 fs 进行采样&#xff0c;进行 N点FFT 选择显示0~N/21点的幅值 横坐标对应频率计算公式&#xff1a; fs * n / N 举个梨子&#xff1a; 频率2kHz采样1s&#xff0c;得到2000个点的序列y(n) 对序列y(n)做4096点的FFT 幅值响应对应的横坐标频率…