【面试题-004】ArrayList 和 LinkList区别

news2024/10/6 22:27:54

文章目录

  • List和set
  • ArrayList扩容机制
  • HashMap扩容机制
  • HashMap初始容量(Initial Capacity)和负载因子(Load Factor)
  • HashMap与HashTable区别 ?HashMap底层数据结构?
  • ConcurrentHashMap底层数据结构?

在这里插入图片描述

ArrayListLinkedList 都是 Java 中常用的动态数组实现,都实现了 List 接口,但它们在内部数据结构和性能方面有所不同:

  1. 内部数据结构:
    • ArrayList 是基于动态数组的数据结构,它允许快速随机访问。数组的大小在创建时是固定的,当数组满时,ArrayList 会自动扩容,创建一个新的更大的数组,并将原数组的内容复制到新数组中。
    • LinkedList 是基于双向链表的数据结构,每个元素都是一个节点,包含数据和两个指针,分别指向前一个节点和后一个节点。链表的特点是元素可以灵活地插入和删除,不需要移动其他元素。
  2. 性能:
    • ArrayList 提供了更快的随机访问和顺序访问速度,时间复杂度为 O(1)。但是,在数组中间插入或删除元素时,需要移动目标位置后的所有元素,时间复杂度为 O(n)。
    • LinkedList 在链表中间插入和删除元素非常快,时间复杂度为 O(1)。但是,随机访问较慢,时间复杂度为 O(n),因为需要从头节点或尾节点开始遍历链表。
  3. 内存占用:
    • ArrayList 由于是基于数组的,需要连续的内存空间,而且在扩容时可能会浪费一些内存(因为新数组可能会留有未使用的空间)。
    • LinkedList 每个元素都需要额外的内存来存储指向前一个和后一个节点的指针,因此在存储大量元素时,可能会比 ArrayList 使用更多的内存。
  4. 适用场景:
    • 当需要频繁进行随机访问操作时,ArrayList 是更好的选择。
    • 当需要频繁在列表中间进行插入和删除操作时,LinkedList 更适合。
      选择 ArrayList 还是 LinkedList 取决于具体的应用场景和对性能的需求。在实际开发中,ArrayList 由于其优异的随机访问性能,通常是最常用的列表实现。只有在特定的场景下,当链表的特性(如频繁的插入和删除操作)能带来明显的性能优势时,才会考虑使用 LinkedList

List和set

Java 提供了丰富的集合框架(Collection Framework),用于存储和管理对象集合。这些集合可以分为几个主要类别:

  1. List(列表):列表是一个有序的集合,可以包含重复的元素。实现 List 接口的类包括:
    • ArrayList:基于动态数组的数据结构,提供快速的随机访问和顺序访问。
    • LinkedList:基于双向链表的数据结构,提供快速的插入和删除操作。
    • Vector:和 ArrayList 类似,但是是同步的,适用于多线程环境。不过,由于同步带来的性能开销,通常建议使用 ArrayList 并自行同步,或者使用并发集合。
  2. Set(集):集是一个无序的集合,不包含重复的元素。实现 Set 接口的类包括:
    • HashSet:基于哈希表实现,提供快速的插入、删除和查找操作。
    • LinkedHashSet:具有 HashSet 的查找效率,并且维护了插入顺序。
    • TreeSet:基于红黑树实现,可以确保元素处于排序状态。
    • EnumSet:用于存放枚举类型,内部使用位向量实现,非常高效。
  3. Queue(队列):队列是一个先进先出(FIFO)的数据结构。实现 Queue 接口的类包括:
    • PriorityQueue:基于优先级堆的无界优先队列。
    • LinkedList:也可以用作队列,因为实现了 Queue 接口。
    • ArrayDeque:是一个可扩容的双端队列,可以作为栈或队列使用。
  4. Deque(双端队列):双端队列允许在队列的两端进行元素的插入和删除。实现 Deque 接口的类包括:
    • ArrayDeque:基于数组的双端队列实现。
    • LinkedList:也可以用作双端队列。
  5. Map(映射):映射是一个键值对集合,键不包含重复的元素。实现 Map 接口的类包括:
    • HashMap:基于哈希表实现,提供快速的查找、插入和删除操作。
    • LinkedHashMap:维护了插入顺序的 HashMap
    • TreeMap:基于红黑树实现,可以确保键处于排序状态。
    • Hashtable:和 HashMap 类似,但是是同步的,适用于多线程环境。同样,由于同步带来的性能开销,通常建议使用 HashMap 并自行同步,或者使用并发集合。
    • EnumMap:键为枚举类型的特殊映射,内部使用数组实现,非常高效。
  6. 并发集合:Java 提供了一些线程安全的集合,用于多线程环境:
    • ConcurrentHashMap:线程安全的 HashMap
    • CopyOnWriteArrayList:线程安全的 ArrayList,适用于读多写少的场景。
    • CopyOnWriteArraySet:线程安全的 Set,适用于读多写少的场景。
    • BlockingQueue:线程安全的队列,用于生产者-消费者模式。
    • ConcurrentLinkedQueue:线程安全的非阻塞队列。
  7. 其他集合
    • Stack:栈是一个后进先出(LIFO)的数据结构,Java 中没有单独的 Stack 类,而是使用 Deque 接口的实现类,如 ArrayDeque,来实现栈的功能。
      这些集合类和接口都在 java.util 包中,除了并发集合,它们大多在 java.util.concurrent 包中。Java 的集合框架提供了丰富的API,使得操作集合变得非常方便和灵活。

ArrayList扩容机制

ArrayList 是 Java 中使用最广泛的动态数组实现之一。它允许我们动态地添加和删除元素,而不需要担心数组的固定大小。ArrayList 的扩容机制是其核心特性之一,下面是它的工作原理:

  1. 初始容量
    • 当我们创建一个 ArrayList 对象时,可以指定一个初始容量,如果没有指定,默认容量为 10。
  2. 扩容时机
    • 当我们尝试添加元素到 ArrayList 中,并且数组的当前大小不足以容纳新元素时,ArrayList 需要进行扩容。
  3. 扩容过程
    • ArrayList 通过一个内部数组来存储元素。当需要扩容时,它会创建一个新的更大的数组(通常是原数组大小的 1.5 倍),然后将原数组中的所有元素复制到新数组中。
    • 这个过程是通过 System.arraycopy() 方法实现的,它是一个本地方法,可以高效地复制数组。
  4. 内存复制
    • 扩容涉及到内存复制,这是一个相对昂贵的操作,因为它需要将所有现有元素从一个数组复制到另一个数组。
    • 因此,虽然 ArrayList 提供了动态添加元素的便利,但在大量添加元素的场景下,频繁的扩容可能会影响性能。
  5. 预分配
    • 为了避免频繁的扩容操作,如果预先知道将要存储的元素数量,可以在创建 ArrayList 时指定一个足够大的初始容量,这样可以减少扩容的次数。
  6. 缩容
    • ArrayList 没有提供自动缩容的功能。如果需要减少存储空间的使用,可以通过调用 trimToSize() 方法来缩小数组的大小以匹配当前元素数量。
      扩容机制是 ArrayList 能够灵活地处理元素数量的变化的关键,但它也带来了性能上的考虑。在实际使用中,根据应用场景和性能要求,合理地管理 ArrayList 的容量是非常重要的。

HashMap扩容机制

HashMap 是 Java 中使用哈希表实现的映射接口,它存储键值对(key-value pairs)。HashMap 的扩容机制是其核心特性之一,用于处理哈希表中的哈希冲突和提高性能。下面是 HashMap 的扩容机制的工作原理:

  1. 初始容量和负载因子
    • 创建 HashMap 时,可以指定初始容量和负载因子。初始容量是哈希表中的桶数,负载因子是哈希表填充程度的度量标准。
  2. 扩容时机
    • HashMap 中的元素数量达到容量和负载因子的乘积时,即 HashMap 的实际大小超过了负载因子与当前容量的乘积,HashMap 就会进行扩容。
  3. 扩容过程
    • 扩容过程涉及创建一个新的更大的数组(通常是原数组大小的两倍),然后将原数组中的所有元素重新哈希并复制到新数组中。
    • 重新哈希是因为哈希表的容量改变了,每个键的哈希值与新容量之间的关系可能会改变,因此需要重新计算每个键的索引位置。
  4. 内存复制
    • 扩容涉及到内存复制,这是一个相对昂贵的操作,因为它需要将所有现有元素从一个数组复制到另一个数组,并重新计算每个元素的哈希值。
    • 这个过程是通过数组的复制和链表的遍历来实现的。
  5. 链表和红黑树
    • HashMap 中,哈希表的每个桶可能包含一个链表或一棵红黑树。当桶中的元素数量超过一定阈值时,链表会转换为红黑树,以提高搜索效率。
    • 扩容时,链表和红黑树中的元素都需要重新哈希和重新组织。
  6. 性能考虑
    • 频繁的扩容可能会影响 HashMap 的性能,因为每次扩容都需要重新哈希和复制所有元素。
    • 为了避免性能问题,如果预先知道将要存储的键值对数量,可以在创建 HashMap 时指定一个足够大的初始容量。
      HashMap 的扩容机制是为了保持哈希表的性能和效率,同时处理哈希冲突。在实际使用中,根据应用场景和性能要求,合理地管理 HashMap 的容量是非常重要的。

HashMap初始容量(Initial Capacity)和负载因子(Load Factor)

在 Java 的 HashMap 中,初始容量(Initial Capacity)和负载因子(Load Factor)是两个重要的参数,它们在创建 HashMap 时可以进行调整,以优化性能和内存使用。

  1. 初始容量
    • 初始容量是指 HashMap 创建时的桶数,即内部数组的大小。默认的初始容量是 16。
    • 设置一个合适的初始容量可以减少扩容操作的次数,从而提高性能。如果预先知道将要存储的键值对数量,可以选择一个接近于预期数量的初始容量,但最好保持为 2 的幂,因为 HashMap 使用哈希值与数组长度的模运算来定位元素,2 的幂可以使得这个运算更高效。
  2. 负载因子
    • 负载因子是衡量 HashMap 填充程度的一个指标,它决定了 HashMap 何时进行扩容。负载因子的默认值是 0.75。
    • 负载因子等于当前元素数量(即键值对的数量)与内部数组大小的比值。当 HashMap 中的元素数量达到负载因子与内部数组大小的乘积时,HashMap 就会进行扩容,通常是容量翻倍。
    • 设置一个较低的负载因子可以减少哈希冲突的概率,但会增加内存的使用和扩容操作的频率。设置一个较高的负载因子可以节省内存,但可能会增加哈希冲突的概率和链表的长度,从而降低性能。
      在实际应用中,选择合适的初始容量和负载因子取决于具体的使用场景。如果对内存使用非常敏感,可以选择一个较高的负载因子。如果对性能要求较高,尤其是在插入和查找操作非常频繁的情况下,可以选择一个较低的负载因子,并设置一个足够大的初始容量以减少扩容操作的次数。

HashMap与HashTable区别 ?HashMap底层数据结构?

HashMapHashtable 都是 Java 中用于存储键值对的数据结构,但它们之间有一些关键的区别:

  1. 同步性
    • HashMap 不是同步的,如果多个线程同时访问并修改 HashMap,必须外部同步。
    • Hashtable 是同步的,它所有的公共方法都是同步的,适用于多线程环境。但是,这会带来性能开销,因为它需要锁定整个表来防止并发修改。
  2. null值和null键
    • HashMap 允许使用一个 null 键和多个 null 值。
    • Hashtable 不允许使用 null 键或 null 值。
  3. 迭代顺序
    • HashMap 提供了更快的迭代速度,并且迭代顺序是不确定的。
    • Hashtable 的迭代速度较慢,并且迭代顺序也是不确定的。
  4. 继承
    • HashMap 继承自 AbstractMap 类。
    • Hashtable 继承自 Dictionary 类,这是一个已经被废弃的类。
  5. 性能
    • HashMap 通常提供比 Hashtable 更好的性能,因为 HashMap 的实现更加优化。
  6. 历史
    • Hashtable 是早期 Java 版本中的实现,而 HashMap 是在 Java 2(JDK 1.2)中引入的。
      HashMap 的底层数据结构是一个数组,数组的每个元素是一个链表(在 Java 8 及更高版本中,链表在达到一定长度后会转换为红黑树以提高性能)。这个数组被称为桶(bucket)数组,每个桶对应一个哈希值。当插入一个键值对时,首先会根据键的哈希值计算出桶的索引,然后将键值对存储在相应的桶中的链表(或红黑树)中。如果两个不同的键产生了相同的哈希值,会发生哈希冲突,这时会在同一个桶中的链表(或红黑树)中存储这两个键值对。
      由于 Hashtable 的许多特性已经被 HashMap 替代,并且 Hashtable 的同步性能较差,通常建议在不需要线程安全的场景下使用 HashMap,在需要线程安全的场景下使用 ConcurrentHashMap

ConcurrentHashMap底层数据结构?

ConcurrentHashMap 是 Java 中的一个线程安全的映射实现,它位于 java.util.concurrent 包中。ConcurrentHashMap 的底层数据结构在 Java 8 及其之后的版本中经历了一些变化,下面是主要的组成:

  1. 节点(Node)
    • ConcurrentHashMap 中的元素以节点(Node)的形式存储,每个节点包含键、值、哈希值和指向下一个节点的指针。
  2. 数组(Segment)(Java 8 之前):
    • 在 Java 8 之前的版本中,ConcurrentHashMap 使用了一个分段锁(Segment)的数据结构,其中内部数组被分割成多个段,每个段是一个独立的锁结构,用于减少锁竞争。
    • 每个段包含一个小的哈希表,用于存储节点。
  3. 桶(Bucket)数组(Java 8 及之后):
    • 从 Java 8 开始,ConcurrentHashMap 的底层数据结构被重新设计,去掉了分段锁,转而使用一个大的桶数组(也称为哈希桶数组或哈希表),类似于 HashMap 的结构。
    • 桶数组中的每个桶可能包含一个链表或一棵树(红黑树),用于解决哈希冲突。
  4. 链表和红黑树
    • 当多个键映射到同一个桶时,这些键值对以链表的形式存储。
    • 在链表长度超过一定阈值后,链表会被转换成红黑树,以提高搜索效率。
  5. CAS(Compare-And-Swap)操作
    • ConcurrentHashMap 使用了无锁算法和 CAS 操作来实现并发安全,这是一种乐观锁策略,它允许在不加锁的情况下对数据进行修改,只有当预期值与实际值相同时才进行更新。
  6. 同步机制
    • ConcurrentHashMap 使用了细粒度的同步机制,只对哈希桶数组中的特定桶进行锁定,而不是整个映射,这大大减少了锁竞争,提高了并发性能。
      ConcurrentHashMap 的设计目的是提供一种高效的线程安全映射,它在多线程环境中提供了良好的并发性能,同时避免了 Hashtable 的全局锁带来的性能瓶颈。

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

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

相关文章

HTML静态网页成品作业(HTML+CSS)—— 美食湘菜介绍网页(5个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有5个页面。 二、作品演示 三、代…

AI 正在攻克难题——赋予计算机嗅觉

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

NLP(1)-TF-IDF算法介绍

一、TF-IDF算法介绍 TF-IDF(term frequency–inverse document frequency,词频-逆向文件频率)是一种用于信息检索(information retrieval)与文本挖掘(text mining)的常用加权技术。 TF-IDF是一…

Java:流程控制语句

文章目录 一、顺序结构二、分支结构2.1 if2.2 switch 三、循环结构3.1 for3.2 while3.3 do...while 四、流程控制4.1 break4.2 continue 五、结语 一、顺序结构 顺序结构语句是Java程序默认的执行流程,按照代码的先后顺序,从上到下依次执行。 二、分支结…

理解NSCopying协议

NSCopying 协议用于让对象能够被复制。实现这个协议的类需要定义如何创建该对象的副本。这个副本是独立的,不会与原对象共享内存地址。 为什么需要 NSCopying 协议? 当你需要复制对象时,例如将对象存储到一个集合(如数组、字典&…

锐捷校园网自助服务-字符过滤存在缺陷

锐捷校园网自助服务-字符过滤存在缺陷 漏洞介绍 令人感到十分遗憾的是,锐捷网络安全应急响应中心对漏洞上报似乎缺少了一些奖励,令人对官方上报漏洞失去了些许兴趣​。 该缺陷仅仅打破了安全检查防护,并没有造成实质性危害,至于…

ChatGPT成知名度最高生成式AI产品,使用频率却不高

5月29日,牛津大学、路透社新闻研究所联合发布了一份生成式AI(AIGC)调查报告。 在今年3月28日—4月30日对美国、英国、法国、日本、丹麦和阿根廷的大约12,217人进行了调查,深度调研他们对生成式AI产品的应用情况。 结果显示&…

Ubuntu22.04下源码编译安装pythonocc-7.8

Ubuntu22.04下源码编译安装pythonocc-7.8 本文介绍Ubuntu下手动编译安装pythonocc,及安装过程遇到的各种坑 基本依赖安装 sudo apt-get update sudo apt-get install -y wget libglu1-mesa-dev libgl1-mesa-dev libxmu-dev libxi-dev build-essential cmake libf…

Angular17(1):使用Angular CLI创建空项目

要创建一个空的 Angular 项目,可以使用 Angular CLI(命令行界面)。以下是使用 Angular CLI 创建一个新项目的步骤: 1、安装 Angular CLI: 打开你的命令行界面(在 Windows 上是 CMD、PowerShell 或 Git Bas…

浮点数精度问题(详细)

文章目录 1.什么是浮点数2. 二进制与十进制的转换2.1 二进制与十进制的相互转换(方法介绍,思维理解)2.2 在线转换工具 3.浮点数的 IEEE754 表示4.C# 浮点型float、double 、decimal 比较5.解决运算精度问题5.1 浮点数预算精度问题5.2 解决方案5.2.1 放大倍数计算5.2…

基于PHP+MySQL开发的一套游泳馆预约报名小程序开发源码模板

最近新开发了一套游泳馆线上预约报名小程序,其主要功能有预约功能,报名功能,支付功能,个人中心,订单管理,商品管理等等。 游泳馆预约报名小程序系统-运行环境 开发语言:PHP 数据库:M…

升级SVN服务器web管理工具EasyPHP17.1

1、卸载EasyPHP12.1,删除C盘安装路径下C:\Program Files (x86)\EasyPHP12**文件 2、安装EasyPHP-Devserver-17.0-setup,链接见下方官网地址 PHP DEVSERVER | LOCAL PHP DEVELOPMENT ENVIRONMENTA complete and ready-to-use PHP development environmen…

MySQL 自定义函数(实验报告)

一、实验名称: 自定义函数 二、实验日期: 2024年 6 月 1 日 三、实验目的: 掌握MySQL自定义函数的创建及调用; 四、实验用的仪器和材料: 硬件:PC电脑一台; 配置:内存&#…

LabVIEW实现汽车逆变器功能测试系统

​介绍了如何利用LabVIEW开发汽车逆变器(包括功率板和控制板)的自动测试设备(ATE),实现对额定800V电压、300A电流的逆变器进行功能测试。系统通过CAN2.0通讯协议,实现电机控制、温度传感器监测、电压校验和…

docker一键部署EFK系统(elasticsearch filebeat kibana metricbeat es-head)

EFK日志系统搭建 EFK日志系统介绍功能需求搭建elasticsearch集群规划前提部署核对证书及权限 EFK日志系统介绍 Elasticsearch 是一个实时的、分布式的可扩展的搜索引擎,允许进行全文、结构化搜索,它通常用于索引和搜索大量日志数据,也可用于…

7、css3实现边框不停地跑动效果

效果例图&#xff1a; 1、上html代码&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><meta …

百分之九十的人都忽视了JMeter响应断言中的这个实用功能—— Jmeter Variable Name to use

JMeter的响应断言 相信对于使用过JMeter的同学来学&#xff0c;一定都使用过响应断言&#xff0c;在这里我就不相信介绍了&#xff0c;我们可以简单的理解为&#xff1a; JMeter的响应断言是一种用于检查测试中得到的响应数据是否符合预期的工具&#xff0c;旨在保证性能测试…

挑战你的数据结构技能:复习题来袭【6】

1. (单选题)设无向图的顶点个数为n,则该图最多有&#xff08;&#xff09;条边 A. n-1 B. n(n-1)/2 C. n(n1)/2 D. 0 答案&#xff1a;B 分析&#xff1a; 2. (单选题)含有n个顶点的连通无向图,其边的个数至少为()。 A. n-1 B. n C. n1 D. nlog2n 答案&#xff1a;A…

产品经理的“高光”时刻,你中了几个?

作为产品经理&#xff0c;都有着这样一个闪闪发光的梦&#xff0c;就是看着自己的产品从0到DAU过万、过十万&#xff0c;甚至是过百万。 不过想要成为过百万的大牛&#xff0c;天时地利任何一个都不能少&#xff0c;大多数的产品经理暂时还在打怪升级攒经验。 虽然暂时体验不…

C++ STL map容器erase操作避坑

map容器的erase方法有三种重载形式&#xff1a; //1.删除迭代器所指向的元素 //返回值是指向下一个节点的迭代器 iterator erase(iterator it); //2.区间删除 iterator erase(iterator first, iterator last); //3.根据键值删除 //返回值为删除的元素个数 size_type erase(con…