LinkedList知识点

一、LinkedList基础知识点

(一)基本概念

LinkedList 是 Java 中一个非常重要的数据结构,属于 java.util 包中的类。它是基于双向链表实现的,既可以作为列表(List)使用,也可以作为队列(Queue)或双端队列(Deque)使用。

(二)链表结构介绍

链表是由一系列非连续的节点组成的存储结构。链表又分为单向链表和双向链表,而单向/双向链表又可以分为循环链表和非循环链表。

  1. 单向链表:每个结点由数据项和指向下一个结点的指针构成,最后一个节点的 next 指向 null
  2. 单向循环链表:和单向列表的不同是,最后一个节点的 next 不是指向 null,而是指向 head 节点,形成一个“环”。
  3. 双向链表:包含两个指针,pre 指向前一个节点,next 指向后一个节点,但是第一个节点 headpre 指向 null,最后一个节点的 tail 指向 null
  4. 双向循环链表:和双向链表的不同在于,第一个节点的 pre 指向最后一个节点,最后一个节点的 next 指向第一个节点,也形成一个“环”。而 LinkedList 就是基于双向循环链表设计的。

(三)LinkedList特点

  1. 数据重复性:数据可重复。
  2. 数据有序性:保证插入数据的有序性。
  3. null值问题:可以有多个 null 值。
  4. 底层数据结构:底层提供的是双向链表。其节点结构如下:
private static class Node<E>{  E item;  Node<E> next;  Node<E> prev;  Node(Node<E> prev, E element, Node<E> next) {  this.item = element;  this.next = next;  this.prev = prev;  } }
  1. 继承关系public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable。LinkedList 直接继承了 AbstractSequentialList 类,该类继承了 AbstractList 类。LinkedList 实现了 List 接口,Deque 接口,可以克隆,可以进行序列化和反序列化操作。
  2. 基本属性
transient int size = 0; // 表示当前集合存储数据个数 transient Node<E> first; // 第一个节点 transient Node<E> last; // 最后一个节点 private static final long serialVersionUID = 876323262645176354L; // 用于 Java 的序列化机制 protected transient int modCount = 0; // 表示的是版本控制,添加,删除,修改之类的操作都会进行 ++ 操作
  1. 构造函数
// 无参构造函数,构造一个空列表 public LinkedList() { } // 使用集合的构造方法,先构造一个空列表,再将集合中所有元素添加到列表中 public LinkedList(Collection<? extends E> c) {  this();  addAll(c); }

(四)常用方法

  1. 添加元素
linkedList.add("Element"); // 在末尾添加元素 linkedList.addFirst("First Element"); // 在开头添加元素 linkedList.addLast("Last Element"); // 在末尾添加元素
  1. 获取元素
E firstElement = linkedList.getFirst(); // 获取头部元素 E lastElement = linkedList.getLast(); // 获取尾部元素 E elementAtIndex = linkedList.get(index); // 根据索引获取元素
  1. 删除元素
linkedList.remove(); // 删除第一个元素并返回 linkedList.remove(index); // 删除指定索引位置的元素并返回 linkedList.remove(Object o); // 删除第一个匹配的元素

二、JDK8之前LinkedList的相关特性和使用情况

(一)JDK1.6及之前

  1. 底层结构:使用的是一个带有头结点的双向循环链表,头结点不存储实际数据。通过一个 header 头指针保存队列头和尾。
private transient Entry<E> header = new Entry<E>(null, null, null); public LinkedList() {  header.next = header.previous = header; }
  1. 增删改查方法:增删改查方法主要依赖 addBeforeremove 等方法,由于有头结点,方法操作的一致性高,流程中 if 判断比较少。

(二)JDK1.7

  1. 底层结构:使用不带头结点的普通的双向链表,增加两个节点指针 firstlast 分别指向首尾节点。
transient int size = 0; transient Node<E> first; transient Node<E> last; public LinkedList() { }
  1. 增删改查方法:变成了 linkBeforeunlink 等方法,因为没有 header 节点,需要用 if 判断的就多一些,总共写了 linkBeforelinkFirstlinkedLastunlinkunlinkFirstunlinkLast 这 6 个方法。

(三)JDK8之前的使用场景

  1. 适合场景:频繁插入和删除操作,因为删除不会发生移位;可以实现队列、栈等数据结构;允许元素重复且非线程安全;维护了元素插入时的顺序。
  2. 不适合场景:随机访问元素效率低,因为需要从头或尾开始遍历链表。

三、JDK8之后LinkedList的改动和新特性

(一)底层结构

JDK8 之后,LinkedList 仍然使用不带头结点的普通双向链表,和 JDK1.7 保持一致。但在一些操作上有小的优化,例如在 addget 等方法中,会先判断 index 是靠近队头还是队尾,来确定从哪个方向遍历链入或查找元素。

if (index < (size >> 1)) {  Node<E> x = first;  for (int i = 0; i < index; i++)  x = x.next;  return x; } else {  Node<E> x = last;  for (int i = size - 1; i > index; i--)  x = x.prev;  return x; }

(二)新方法支持 Stream API

Java 8 为集合框架中添加了 stream()parallelStream() 方法,支持流式处理集合中的数据。

import java.util.LinkedList; import java.util.List;  public class LinkedListStreamExample {  public static void main(String[] args) {  List<String> names = new LinkedList<>();  names.add("张三");  names.add("李四");  names.add("王五");  names.stream()  .filter(name -> name.startsWith("张"))  .forEach(System.out::println);  } }

(三)使用 List.sort() 方法对 LinkedList 进行排序

  1. 默认排序(自然顺序)List.sort() 方法使用元素的自然顺序对其进行排序,即按升序排列,前提是这些元素实现了 Comparable 接口。
import java.util.LinkedList; import java.util.List;  public class DefaultSortExample {  public static void main(String[] args) {  List<Integer> list = new LinkedList<>();  list.add(5);  list.add(2);  list.add(8);  list.add(1);  list.add(3);  list.sort(null); // null 表示使用元素的自然顺序  System.out.println("按自然顺序排序后的列表: " + list);  } }
  1. 使用自定义 Comparator 进行排序:如果需要按照自定义的规则对 LinkedList 进行排序,可以传递一个 ComparatorList.sort() 方法。
import java.util.LinkedList; import java.util.List; import java.util.Comparator;  public class CustomSortExample {  public static void main(String[] args) {  List<Integer> list = new LinkedList<>();  list.add(5);  list.add(2);  list.add(8);  list.add(1);  list.add(3);  list.sort(Comparator.reverseOrder()); // 降序排序  System.out.println("按降序排序后的列表: " + list);  } }

四、JDK8前后的详细对比

(一)底层结构对比

  • JDK8之前(以JDK1.6和JDK1.7为例):JDK1.6 使用带有头结点的双向循环链表,JDK1.7 使用不带头结点的普通双向链表。
  • JDK8之后:继续沿用 JDK1.7 的不带头结点的普通双向链表结构,但在一些操作上有小的优化,如根据 index 位置选择遍历方向。

(二)增删改查方法对比

  • JDK8之前:JDK1.6 主要依赖 addBeforeremove 等方法,JDK1.7 变成了 linkBeforeunlink 等方法。
  • JDK8之后:方法基本保持一致,但在查找节点时会根据 index 位置优化遍历方向,提高一定的查找效率。

(三)新特性对比

  • JDK8之前:主要提供基本的增删改查和队列、栈等操作。
  • JDK8之后:支持 Stream API 进行流式处理,提供 List.sort() 方法进行排序,增强了代码的可读性和灵活性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值