Java中LinkedList删除元素

本文介绍在使用Java的迭代器遍历列表过程中正确删除元素的方法。文章通过实例对比了直接使用列表的remove方法与使用迭代器的remove方法的区别,并解释了为何使用列表的remove方法会导致程序异常。

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

今天敲代码看到一个例子,在迭代器遍历的时候插入元素报错,有提到原因,但没有提到删除元素的方法,就自己试了一下
import java.util.*;

public class IteratorTest {
    public static void main(String[] args) {
	List<String> ll = new LinkedList<String>();
	ll.add("ad");
	ll.add("bd");
	ll.add("dd");
	ll.add("dd");

	for (Iterator<String> dd = ll.iterator(); dd.hasNext();) {
	    String str = dd.next();
	    System.out.println(str);
	    if (str.equals("bd")) {
		ll.remove(str);
	    }
	}
	System.out.println(ll);
    }
}

出现了以下的错误

然后很奇怪,就去上网查了出现这样的原因。最后找到了,虽然用到了迭代器,但删除用错了方法。原因是当Iterator.remove方法导致LinkedList列表发生变化时,它会更新cursor来同步这一变化。但其他方式导致的LinkedList变化,Iterator是无法感知的。LinkedList不会主动通知Iterator。Iterator做checkForComodification检查,就以异常抛出,所以就出现了上面的异常。,这里需要将 ll.remove(str)改为 dd.remove()

import java.util.*;

public class IteratorTest {
    public static void main(String[] args) {
	List<String> ll = new LinkedList<String>();
	ll.add("ad");
	ll.add("bd");
	ll.add("dd");
	ll.add("dd");

	for (Iterator<String> dd = ll.iterator(); dd.hasNext();) {
	    String str = dd.next();
	    System.out.println(str);
	    if (str.equals("bd")) {
		dd.remove();
	    }
	}
	System.out.println(ll);
    }
}

这样就正常运行,结果也无误了


<think>首先,用户的问题是:“我想了解JavaLinkedList添加元素的不同方法 请问Java LinkedList 添加元素的几种方法”。我需要基于提供的引用信息来回答。 回顾系统级指令: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 参考的引用: - [^1]: Java LinkedList的基本语法和创建方法。 - [^2]: LinkedList的add()方法使用示例。 - [^3]: LinkedList添加元素的性能分析。 - [^4]: LinkedList的常用方法列表。 用户的问题是关于LinkedList添加元素的几种方法,所以我需要从引用中提取相关信息。 关键点: - 从[^2]:add()方法用于添加元素,包括默认位置(末尾)和指定位置。 - 从[^4]:列出了多个方法:add(E o), add(int index, E element), addFirst(E o), addLast(E o)。 - 从[^3]:讨论了性能:默认添加(O(1)),指定位置添加(O(n)),因为需要遍历。 添加元素的方法: 1. add(E e) - 添加到末尾。 2. add(int index, E element) - 添加到指定位置。 3. addFirst(E e) - 添加到开头。 4. addLast(E e) - 添加到末尾(与add(E e)相同)。 5. addAll(Collection c) - 添加集合中的所有元素。 6. addAll(int index, Collection c) - 从指定位置添加集合中的所有元素。 我需要确保回答结构清晰: - 逐步解释每种方法。 - 提供示例代码。 - 讨论性能差异。 - 自然地添加引用标识。 回答结构: 1. 介绍LinkedList的基本概念(简要)。 2. 列出添加元素的不同方法。 3. 详细解释每种方法,包括语法、用法和示例。 4. 讨论性能。 5. 总结。 6. 生成相关问题。 使用中文回答。 生成相关问题:在回答结束后,添加“相关问题”部分。 现在,构建回答: - 开头:直接回答问题。 - 主体:分点解释方法。 - 结尾:总结和生成相关问题。 引用标识: - 在相关段落末尾添加[^n]。 例如: - 提到添加方法时,引用[^2]和[^4]。 - 提到性能时,引用[^3]。 代码示例:从[^2]中提取。 最终回答:</think>### Java LinkedList 添加元素的几种方法 在 Java 中,`LinkedList` 是一种双向链表实现的集合类,适用于频繁插入和删除元素的场景。它提供了多种添加元素的方法,每种方法针对不同的需求。下面我将逐步解释这些方法,包括语法、使用示例、性能差异,并提供代码示例。所有解释基于 Java 标准库的文档和性能分析[^1][^2][^3][^4]。 #### 1. **`add(E e)`:默认添加到末尾** - **描述**:此方法将元素添加到 `LinkedList` 的末尾。这是最常用的方法,时间复杂度为 $O(1)$(常数时间),因为链表尾部有直接引用[^3][^4]。 - **语法**:`boolean add(E e)` - **示例代码**: ```java LinkedList<String> list = new LinkedList<>(); list.add("Apple"); // 添加元素到末尾 list.add("Banana"); System.out.println(list); // 输出: [Apple, Banana] ``` - **性能**:高效,适用于顺序添加元素,无需遍历链表[^3]。 #### 2. **`add(int index, E element)`:添加到指定位置** - **描述**:在链表的指定索引位置插入元素。如果索引超出范围,会抛出 `IndexOutOfBoundsException`。时间复杂度为 $O(n)$(线性时间),因为需要遍历链表到指定位置[^3][^4]。 - **语法**:`void add(int index, E element)` - **示例代码**: ```java LinkedList<String> list = new LinkedList<>(); list.add("Apple"); list.add(0, "Banana"); // 在索引 0 处插入元素 System.out.println(list); // 输出: [Banana, Apple] ``` - **性能**:效率较低,尤其当索引在链表中间时,需要二分查找定位(时间复杂度 $O(\log n)$ 到 $O(n)$)[^3]。 #### 3. **`addFirst(E e)`:添加到开头** - **描述**:将元素插入到链表的头部(开头)。时间复杂度为 $O(1)$,因为链表头部有直接引用[^3][^4]。 - **语法**:`void addFirst(E e)` - **示例代码**: ```java LinkedList<String> list = new LinkedList<>(); list.add("Apple"); list.addFirst("Banana"); // 添加到开头 System.out.println(list); // 输出: [Banana, Apple] ``` - **性能**:高效,适用于实现栈或队列的开头操作[^3]。 #### 4. **`addLast(E e)`:添加到末尾** - **描述**:与 `add(E e)` 方法等效,将元素添加到链表的末尾。时间复杂度为 $O(1)$[^3][^4]。 - **语法**:`void addLast(E e)` - **示例代码**: ```java LinkedList<String> list = new LinkedList<>(); list.add("Apple"); list.addLast("Banana"); // 添加到末尾 System.out.println(list); // 输出: [Apple, Banana] ``` - **性能**:高效,适合需要显式指定末尾添加的场景[^4]。 #### 5. **`addAll(Collection<? extends E> c)`:添加整个集合到末尾** - **描述**:将一个集合的所有元素添加到链表的末尾。时间复杂度取决于集合大小,平均为 $O(m)$($m$ 是集合元素数)[^4]。 - **语法**:`boolean addAll(Collection<? extends E> c)` - **示例代码**: ```java LinkedList<String> list = new LinkedList<>(); list.add("Apple"); List<String> fruits = Arrays.asList("Banana", "Cherry"); list.addAll(fruits); // 添加整个集合到末尾 System.out.println(list); // 输出: [Apple, Banana, Cherry] ``` #### 6. **`addAll(int index, Collection<? extends E> c)`:在指定位置添加整个集合** - **描述**:从链表的指定索引位置开始插入一个集合的所有元素。时间复杂度为 $O(n + m)$($n$ 是链表长度,$m$ 是集合大小),因为需要遍历到索引位置[^4]。 - **语法**:`boolean addAll(int index, Collection<? extends E> c)` - **示例代码**: ```java LinkedList<String> list = new LinkedList<>(); list.add("Apple"); List<String> fruits = Arrays.asList("Banana", "Cherry"); list.addAll(1, fruits); // 在索引 1 处插入集合 System.out.println(list); // 输出: [Apple, Banana, Cherry] ``` ### 性能总结 - **高效方法($O(1)$)**:`add(E e)`, `addFirst(E e)`, `addLast(E e)`。这些方法直接操作链表头或尾,无需遍历。 - **低效方法($O(n)$ 或更高)**:`add(int index, E element)`, `addAll(int index, Collection c)`。这些方法需要遍历链表定位索引,在大型数据集中性能较差[^3]。 - **建议**:如果需要频繁在开头或末尾添加元素,优先使用 `addFirst` 或 `addLast`;避免在中间位置大量添加元素,以防性能下降[^3][^4]。 ### 完整示例代码 ```java import java.util.LinkedList; import java.util.Arrays; import java.util.List; public class LinkedListExample { public static void main(String[] args) { LinkedList<String> list = new LinkedList<>(); // 添加元素到末尾 list.add("Apple"); // 添加到开头 list.addFirst("Banana"); // 添加到指定位置 list.add(1, "Cherry"); // 添加整个集合到末尾 List<String> moreFruits = Arrays.asList("Date", "Fig"); list.addAll(moreFruits); System.out.println("Final List: " + list); // 输出: [Banana, Cherry, Apple, Date, Fig] } } ``` ### 相关问题 1. LinkedList 和 ArrayList 在添加元素时性能有何差异? 2. 如何优化 LinkedList 在中间位置添加元素的性能? 3. LinkedList 在哪些实际应用场景中比 ArrayList 更合适? [^1]: Java LinkedList 的基本语法和创建方法。 [^2]: LinkedList 的 add() 方法使用示例。 [^3]: LinkedList 添加元素的性能分析,包括时间复杂度。 [^4]: LinkedList 的常用方法列表和描述。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值