T9移动架构师成长路线学习第二天(必备数据结构_LinkedList)

一、LinkedList

1、LinkedList的概念

LinkedList 是一个基于双向链表实现的集合类,它允许包含所有元素(包括 null),并且支持在列表的两端进行高效的插入和删除操作,但查找删除慢(需要从头/尾往中间找)。

这里用一个比喻通俗的理解一下:做游戏时每个人手拉手站成一排(LinkedList)。每个人都知道自己的左边和右边是谁(双向链表)。如果想找到队伍中的第5个人,就必须从头开始一个个数到第5个,因为LinkedList是没有下标的(查找删除慢)。但是如果有人要离开队伍,只需要让他的左右两个人重新牵手就行了;如果有人要插队,也只需要在他要插入的位置,让左右两个人松手,然后和新来的人牵手(高效的插入和删除操作)。

2、LinkedList的底层逻辑

LinkedList的底层不是数组(所以无下标),而是一串节点(Node)相互链接,每个节点有三个部分:(1)数据(item);(2)指向前驱节点的引用(prev);(3)指向后继节点的引用(next);

JDK源码中的内部静态类:

ini 复制代码
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;
    }
}

LinkedList 内部维护两个指针:first(头结点)和 last(尾结点),用于快速找到链子两端。这样的话,如果要在头部或尾部插入/删除,只需要改一下这两个指针,不用遍历整个链子。

java 复制代码
transient int size = 0;     // 当前元素个数
transient Node<E> first;    // 头结点
transient Node<E> last;     // 尾结点

3、LinkedList的列表代码实战

LinkedList基本概念就讲到这里,让我们用代码实战一下吧!

代码示例:

csharp 复制代码
import java.util.LinkedList;

public class LinkedListAsListDemo {
    public static void main(String[] args) {
        // 1. 创建一个 LinkedList(当作顺序表)
        LinkedList<String> list = new LinkedList<>();

        // 增(Add)---------------------------------------------------
        list.add("A"); // 在末尾添加
        list.add("B");
        list.add("C");
        list.add(1, "D"); // 在下标 1 的位置插入元素

        System.out.println("添加后的列表: " + list);

        // 查(Read)---------------------------------------------------
        String first = list.get(0);  // 通过下标读取
        String second = list.get(1);
        System.out.println("第一个元素: " + first);
        System.out.println("第二个元素: " + second);

        // 改(Update)---------------------------------------------------
        list.set(2, "E"); // 修改下标为 2 的元素
        System.out.println("修改后的列表: " + list);

        // 删(Delete)---------------------------------------------------
        list.remove(1);        // 删除下标为 1 的元素
        list.remove("C");      // 删除指定对象(第一次出现的)
        System.out.println("删除后的列表: " + list);

        // 遍历(for-each)
        System.out.print("遍历列表: ");
        for (String s : list) {
            System.out.print(s + " ");
        }
    }
}

运行结果:

说明:代码中使用了0、1等下标,比如list.set(2, "E"),这个里面的"2"是index;"E"是item。这并不是错误,因为LinkedList实现了List接口,而List接口定义了按index(下标)操作的方法,所以LinkedList也需要遵循这种方法。

List接口中index的定义:

arduino 复制代码
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);

比如当在代码中调用list.get(3)的时候,并不是像ArrayList那样通过O(1)直接拿到,而是需要判断 index 靠近头还是尾,然后选择近的一端开始遍历,直到找到目标 index 对应的节点。这个操作的底层逻辑还是遍历链表,并不是数组的随机访问。

4、LinkedList实现的接口

LinkedList实现了 List、Deque、Queue 接口,所以既能当顺序表用,又能当队列/栈用。

接口源码示例:

csharp 复制代码
public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
    // ...
}

说明:

(1)implements List:支持按索引的增删查改(把它当顺序表用)。

(2)implements Deque:提供双端队列接口(左右两端的入队/出队/查看),Deque 继承自 Queue,因此也满足 Queue 的一切语义。

(3)底层为 Node(含 item, next, prev),并维护 first 和 last 两个引用(链表两端)。

这个先暂时分享到这里,等学习到队列和栈的时候在进行详细说明。

二、LinkedList和ArrayList的用法对比

特点 ArrayList LinkedList
底层结构 动态数组 双向链表
随机访问(get / set) ,O(1) ,O(n)
插入/删除(中间位置) ,要移动元素 O(n) ,只改指针 O(1)
插入/删除(末尾 add/removeLast) ,均摊 O(1) ,O(1)
内存占用 小(只存数据) 大(额外存指针)
适用场景 读多写少、随机访问多 写多读少、频繁插入删除

ArrayList 适合:频繁访问元素(比如查找、遍历),内存紧张场景。

LinkedList 适合:频繁在中间插入/删除元素,不太在乎访问速度的场景。

因为ArrayList和LinkedList都实现了List接口,所以在编写代码时用的API几乎是一样的,下面举出一个代码实例 :

csharp 复制代码
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ListCompareDemo {
    public static void main(String[] args) {
        // ArrayList 示例
        List<String> arrayList = new ArrayList<>();
        arrayList.add("A");
        arrayList.add("B");
        arrayList.add("C");

        // LinkedList 示例
        List<String> linkedList = new LinkedList<>();
        linkedList.add("A");
        linkedList.add("B");
        linkedList.add("C");

        // 常见操作
        System.out.println("ArrayList 第一个元素: " + arrayList.get(0));
        System.out.println("LinkedList 第一个元素: " + linkedList.get(0));

        arrayList.remove(1);  // 删除 index=1 的元素
        linkedList.remove(1);

        System.out.println("ArrayList 剩余: " + arrayList);
        System.out.println("LinkedList 剩余: " + linkedList);
    }
}

运行结果:

今天的学习就到这里啦,有什么不足还请指正!下期将会学习队列和栈。

相关推荐
火电牛马9 小时前
数据结构(单链表)
数据结构
kk”9 小时前
希尔排序。
c语言·数据结构·笔记·排序算法
微露清风9 小时前
系统性学习数据结构-第二讲-顺序表与链表
数据结构·学习·链表
Tim_1012 小时前
【算法专题训练】17、双向链表
数据结构·c++·算法·链表
ZCollapsar.12 小时前
数据结构 04(线性:双向链表)
c语言·数据结构·学习·算法·链表
YA10JUN12 小时前
数据结构基础--最小生成树
数据结构·算法·图论
lifallen13 小时前
深入了解Flink核心:Slot资源管理机制
大数据·数据结构·数据库·算法·flink·apache
序属秋秋秋13 小时前
《C++进阶之STL》【红黑树】
开发语言·数据结构·c++·笔记·学习·stl
.桂花载酒.13 小时前
数据结构8---排序
数据结构