欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > java-Linkedlist源码分析

java-Linkedlist源码分析

2024/10/24 4:31:36 来源:https://blog.csdn.net/weixin_41247813/article/details/140214726  浏览:    关键词:java-Linkedlist源码分析

## 深入分析 Java 中的 `LinkedList` 源码

`LinkedList` 是 Java 集合框架中的一个重要类,它基于双向链表实现,提供了高效的插入和删除操作。与 `ArrayList` 不同,`LinkedList` 的结构使其在特定操作上有更优的性能表现。本文将详细分析 `LinkedList` 的源码,包括其数据结构、构造方法、核心操作等。

### 1. `LinkedList` 的基本数据结构

`LinkedList` 是基于双向链表实现的,这意味着每个节点都包含对前一个节点和后一个节点的引用。`LinkedList` 主要由以下几个关键字段组成:

```java
public class LinkedList<E> extends AbstractSequentialList<E>
        implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
    transient int size = 0;
    transient Node<E> first;
    transient Node<E> last;

    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;
        }
    }
}
```

- `size`:链表中的元素数量。
- `first`:指向链表的第一个节点。
- `last`:指向链表的最后一个节点。
- `Node`:链表节点的内部类,每个节点包含元素数据和前后节点的引用。

### 2. 构造方法

`LinkedList` 提供了多个构造方法:

#### 2.1 默认构造方法

```java
public LinkedList() {
}
```

默认构造方法初始化一个空的链表。

#### 2.2 从另一个集合创建 `LinkedList`

```java
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}
```

此构造方法从另一个集合创建 `LinkedList`,并将集合中的所有元素添加到链表中。

### 3. 核心操作方法

#### 3.1 添加元素

`LinkedList` 提供了多种添加元素的方法:

##### 3.1.1 在链表末尾添加元素

```java
public boolean add(E e) {
    linkLast(e);
    return true;
}

void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}
```

- `add(E e)`:在链表末尾添加元素。
- `linkLast(E e)`:将新节点链接到链表的末尾。如果链表为空,则新节点既是 `first` 也是 `last`。

##### 3.1.2 在指定位置插入元素

```java
public void add(int index, E element) {
    checkPositionIndex(index);

    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}

void linkBefore(E e, Node<E> succ) {
    final Node<E> pred = succ.prev;
    final Node<E> newNode = new Node<>(pred, e, succ);
    succ.prev = newNode;
    if (pred == null)
        first = newNode;
    else
        pred.next = newNode;
    size++;
    modCount++;
}
```

- `add(int index, E element)`:在指定位置插入元素。
- `linkBefore(E e, Node<E> succ)`:在指定节点之前插入新节点。
- `node(int index)`:返回指定位置的节点。

##### 3.1.3 添加元素到链表的头部

```java
public void addFirst(E e) {
    linkFirst(e);
}

void linkFirst(E e) {
    final Node<E> f = first;
    final Node<E> newNode = new Node<>(null, e, f);
    first = newNode;
    if (f == null)
        last = newNode;
    else
        f.prev = newNode;
    size++;
    modCount++;
}
```

- `addFirst(E e)`:在链表头部添加元素。
- `linkFirst(E e)`:将新节点链接到链表的头部。如果链表为空,则新节点既是 `first` 也是 `last`。

#### 3.2 删除元素

`LinkedList` 提供了多种删除元素的方法:

##### 3.2.1 删除指定位置的元素

```java
public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
}

E unlink(Node<E> x) {
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;

    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }

    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }

    x.item = null;
    size--;
    modCount++;
    return element;
}
```

- `remove(int index)`:删除指定位置的元素。
- `unlink(Node<E> x)`:断开指定节点的链接,并返回节点中的元素。

##### 3.2.2 删除链表的头部元素

```java
public E removeFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return unlinkFirst(f);
}

private E unlinkFirst(Node<E> f) {
    final E element = f.item;
    final Node<E> next = f.next;
    f.item = null;
    f.next = null; // help GC
    first = next;
    if (next == null)
        last = null;
    else
        next.prev = null;
    size--;
    modCount++;
    return element;
}
```

- `removeFirst()`:删除链表的头部元素。
- `unlinkFirst(Node<E> f)`:断开头部节点的链接,并返回节点中的元素。

##### 3.2.3 删除链表的尾部元素

```java
public E removeLast() {
    final Node<E> l = last;
    if (l == null)
        throw new NoSuchElementException();
    return unlinkLast(l);
}

private E unlinkLast(Node<E> l) {
    final E element = l.item;
    final Node<E> prev = l.prev;
    l.item = null;
    l.prev = null; // help GC
    last = prev;
    if (prev == null)
        first = null;
    else
        prev.next = null;
    size--;
    modCount++;
    return element;
}
```

- `removeLast()`:删除链表的尾部元素。
- `unlinkLast(Node<E> l)`:断开尾部节点的链接,并返回节点中的元素。

#### 3.3 获取元素和修改元素

`LinkedList` 提供了获取和修改元素的方法:

##### 3.3.1 获取元素

```java
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

Node<E> node(int 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;
    }
}
```

- `get(int index)`:根据索引获取元素。
- `node(int index)`:返回指定位置的节点,通过判断索引位置决定从前往后还是从后往前遍历,提高效率。

##### 3.3.2 修改元素

```java
public E set(int index, E element) {
    checkElementIndex(index);
    Node<E> x = node(index);
    E oldVal = x.item;
    x.item = element;
    return oldVal;
}
```

- `set(int index, E element)`:根据索引修改元素,并返回旧元素。

### 4. 双向链表的结构特点

#### 4.1 链表节点的定义

在 `LinkedList` 中,每个节点包含一个元素和对前后节点的引用:

```java
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;
    }
}
```

- `item`:存储节点的元素。
- `next`:指向下一个节点。
- `prev`:指向前一个节点。

#### 4.2 链表的首尾节点

`LinkedList` 通过 `first` 和 `last` 字段分别指向链表的首节点和尾节点,这样可以高效地进行头部和尾部的插入和删除操作。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com