ArrayList和LinkedList原理

本文探讨了ArrayList和LinkedList这两种数据结构的特点。ArrayList适用于需要快速访问元素的场景,而LinkedList则更适合频繁进行元素插入和删除的操作。文章详细解释了两种数据结构在不同操作下的性能表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


ArrayList:

ArrayList 使用默认无参数构造函数,底层的Object数组长度默认为10,当长度不够用自动增长0.5倍

源代码:

默认长度10

[java]  view plain  copy
  1. /** 
  2.  * Default initial capacity. 
  3.  */  
  4. private static final int DEFAULT_CAPACITY = 10;  


如果数组长度不够增长0.5倍grow方法

[java]  view plain  copy
  1. int newCapacity = oldCapacity + (oldCapacity >> 1);  

ArrayList为什么查询快,增删慢?

查询快:

因为数组的内存地址排列是连续的,可以很快找到比如 list.get(100); 第一个元素内存地址是0x98,那么内存地址加100就找到了。

增删慢:

增:

我们假设这个数组长度容量为7,现在要再添加一个元素它会怎么做呢?

增加元素时,先检测数组长度是否够用,如果底层Object数组长度不够,增加0.5倍的长度,形成一个新的Object数组,并将之前的数组元素copy到新的数组里面。


删:

 

删除慢:当删除里面的其中一个数据时,后面的数据要全部移动一个位置。


LinkedList:

使用链表数据结构实现,特点,增删快,查询慢。

查询慢:元素之前内存地址不连续,只能挨个挨个遍历查找


增加:

插入数据时,只需要改变内存地址的指向;


将和它有关系的内存地址指向删除掉,没人指向它,它就成为了垃圾对象。

<think>嗯,用户想比较C#中的ArrayListLinkedList的特点及适用场景。首先,我需要确认C#中这些数据结构的具体实现。不过,C#的ArrayListLinkedList可能与Java中的有所不同,需要先查证。 根据引用内容,Java中的ArrayList是基于动态数组,LinkedList是双向链表。那在C#中,ArrayList应该也是动态数组,而LinkedList可能同样是链表结构。不过C#的List<T>类似于Java的ArrayList,而LinkedList<T>是专门的双向链表。可能用户提到的ArrayList是旧的非泛型集合,而通常推荐使用泛型版本List<T>,但这里还是按用户的问题来回答。 接下来,性能对比方面,引用提到ArrayList在随机访问快,插入删除慢;LinkedList则相反。这同样适用于C#的情况。需要说明两者的底层结构差异带来的性能差异,比如数组的连续内存链表的节点链接。 然后,适用场景部分,引用中的信息指出ArrayList适合查询多、增删少的场景,LinkedList适合频繁插入删除。需要结合C#的具体情况,比如在中间操作时LinkedList的性能优势,但头部或尾部可能ArrayList也有不同的表现,比如C#的List<T>在尾部添加效率高,因为动态数组会预留空间。 另外,用户可能混淆了C#中的ArrayListList<T>,因为ArrayList是非泛型的,而List<T>是泛型版本,更常用。需要指出这一点,但根据问题描述,还是以ArrayListLinkedList对比为主。 还要注意C#的LinkedList<T>是否支持索引访问,可能不支持,因此随机访问效率低。需要强调两者的访问方式差异,比如LinkedList需要遍历节点,而ArrayList可以直接通过索引。 最后,需要总结两者的优缺点,并给出使用场景建议,比如处理大量中间插入删除用LinkedList,而需要快速随机访问用ArrayList或List<T>。同时提醒用户考虑线程安全等因素,可能推荐使用泛型集合。 可能需要检查C#文档确认具体细节,比如动态数组的扩容机制,LinkedList的方法等,确保回答准确。同时,引用中的资料虽然来自Java,但数据结构原理相通,可以类比,但要指出C#中的实现差异。</think>### C# ArrayListLinkedList 特点及性能对比 #### 1. **底层结构差异** - **`ArrayList`**(非泛型动态数组): - 底层基于动态数组实现,内存连续分配,支持快速随机访问(时间复杂度 $O(1)$)。 - 插入/删除元素时,若涉及中间位置操作,需要移动后续元素,时间复杂度为 $O(n)$[^1][^4]。 - 扩容时需重新分配内存并复制数据,可能影响性能[^3]。 - 示例代码: ```csharp ArrayList list = new ArrayList(); list.Add(10); // 动态扩容 int value = (int)list[0]; // 直接索引访问 ``` - **`LinkedList<T>`**(泛型双向链表): - 底层基于双向链表,内存非连续分配,每个节点包含前驱后继指针。 - 插入/删除元素时,仅需修改相邻节点指针,时间复杂度为 $O(1)$(需先定位到操作位置)。 - 随机访问需从头/尾遍历链表,时间复杂度为 $O(n)$[^5]。 --- #### 2. **性能对比** | **操作** | **`ArrayList`** | **`LinkedList<T>`** | |-------------------|---------------------|---------------------| | 随机访问(索引) | $O(1)$ | $O(n)$ | | 头部插入/删除 | $O(n)$ | $O(1)$ | | 尾部插入/删除 | $O(1)$(均摊) | $O(1)$ | | 中间插入/删除 | $O(n)$ | $O(n)$(需遍历定位)| | 内存占用 | 连续内存,无指针开销 | 分散内存,每个节点含指针 | --- #### 3. **适用场景** - **优先选择 `ArrayList`/`List<T>`**: - 需要频繁随机访问元素(如按索引查询)。 - 尾部插入/删除操作较多(动态数组优化了尾部操作)。 - 示例场景:数据缓存、批量数据处理。 - **优先选择 `LinkedList<T>`**: - 频繁在头部或中间插入/删除元素(如实现队列、栈或双向链表结构)。 - 不需要按索引访问,而是通过遍历操作(如实现 LRU 缓存淘汰算法)[^5]。 - 示例场景:实时日志记录、撤销操作历史记录。 --- #### 4. **实际测试结论** - **查询性能**:`ArrayList` 的索引访问速度显著优于 `LinkedList<T>`。 - **插入/删除性能**: - 在头部操作时,`LinkedList<T>` 性能优势明显(无需移动元素)[^5]。 - 在中间操作时,若已定位到节点,`LinkedList<T>` 效率更高;否则需额外遍历时间。 --- #### 5. **总结建议** - 若需**泛型支持**,优先使用 `List<T>`(C# 中更现代的替代方案,类型安全且性能优于 `ArrayList`)。 - 若需**频繁增删且无需索引访问**,选择 `LinkedList<T>`。 - 若需**高性能随机访问或尾部操作**,选择 `List<T>` 或 `ArrayList`(非泛型场景)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值