[数据结构] LinkedList

发布于:2025-09-10 ⋅ 阅读:(17) ⋅ 点赞:(0)

1. 什么是 LinkedList

  LinkedList (官方文档)

LinkedList是Java集合框架中的一个双向链表实现,位于java.util包中。它实现了ListDeque接口,支持高效的插入和删除操作,但随机访问性能较差


2. LinkedList 的 特性

  • 双向链表结构:每个节点(Node)包含前驱(prev)、后继(next)和当前元素(item)的引用
  • 非连续内存存储:与ArrayList不同,LinkedList的元素在内存中不连续存储
  • 动态大小:无需预先分配空间,大小随元素增减动态变化


3. LinkedList 实现的接口

  • LinkedList 实现了 List 接口
  • LinkedList 的底层是使用了双向链表
  • LinkedList 没有实现 RandomAccess 接口 , 因此 LinkedList 不支持随机访问
  • LinkedList 的任意插入和删除元素时效率比较高效 , 时间复杂度为O(1)
  • LinkedList 比较适合任意位置插入的场景

4. LinkedList 的使用

4.1 LinkedList 的创建

① LinkedList 的创建

    public static void main(String[] args) {
        List<Integer> list1 = new LinkedList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);
        System.out.println(list1);
    }

② 用 ArrayList 来构造 LinkedList

    public static void main(String[] args) {
        List<Integer> list2 = new java.util.ArrayList<>();
        list2.add(22);
        list2.add(122);
        list2.add(233);
        list2.add(344);
        System.out.println(list2);
        List<Integer> list3 = new LinkedList<>(list2);
    }

4.2 LinkedList 常用方法的介绍

方法 解释
 boolean add (E e) 尾插 e
void add (int index , E element) 将 e 插入到 index 位置
boolean addAll (Collection<? extends E> c) 尾插 c 中的元素
E remove (int index) 删除 index 位置的元素
boolead remove (Object o) 删除遇到的第一个元素 o
E get (int index) 获取下标 index 的元素
E set (int index , E element) 将下标 index 位置的元素设置为 element
void clear () 清空
boolean contains (Object o) 判断 o 是否包含在线性表中
int indexOf (Object o) 返回第一个 o 所在位置的下标
int lastindexOf (Object o) 返回最后一个 o 所在位置的下标
List<E> subList (int fromIndex , int toIndex) 截取部分 list

部分方法演示

    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(11);
        list.add(22);
        list.add(33);
        list.add(44);
        list.add(99);
        list.add(22);
        System.out.println(list);//[11, 22, 33, 44, 99, 22]

        list.add(0,88);//指定位置插入
        System.out.println(list);//[88, 11, 22, 33, 44, 99, 22]

        list.remove(0);//删除指定下标元素
        list.removeFirst();//删除第一个元素
        list.removeLast();//删除最后一个元素
        System.out.println(list);//[22, 33, 44, 99]

        list.set(3,00);//将下标为3的元素设置为0
        System.out.println(list);//[22, 33, 44, 0]

        List<Integer> list1 = list.subList(0,4);//截取list 从[0,4)下标 并复制为新的链表
        System.out.println(list1);//[22, 33, 44, 0]

        list.clear();//清空链表
        System.out.println(list);//[]
    }

4.3 LinkedList 的遍历

注意 : 以下代码省略了 main 方法

        LinkedList<Integer> list = new LinkedList<>();
        list.add(11);
        list.add(22);
        list.add(33);
        list.add(44);
        list.add(99);
        list.add(22);

① for each 遍历

        //for each 遍历
        for (int e:list) {
            System.out.print(e+" ");//11 22 33 44 99 22
        }
        System.out.println();

② for 循环遍历

        //for 循环遍历
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i)+" ");//11 22 33 44 99 22
        }
        System.out.println();

③ 迭代器遍历(正向遍历)

        //迭代器遍历(正向遍历)
        ListIterator<Integer> it = list.listIterator();
        while (it.hasNext()){
            System.out.print(it.next()+" ");//11 22 33 44 99 22
        }
        System.out.println();

④ 迭代器遍历(方向遍历)

        ListIterator<Integer> it1 = list.listIterator(list.size());
        while (it1.hasPrevious()){
            System.out.print(it1.previous()+" ");//22 99 44 33 22 11
        }
        System.out.println();

5. LinkedList 与 ArrayList 的对比

5.1 场景选择

场景 推荐使用 原因
频繁随机访问 ArrayList 基于数组的索引访问效率更高(O (1))
频繁插入删除 LinkedList 链表结构修改引用即可,无需移动元素
内存敏感场景 ArrayList 链表节点有额外内存开销
作为队列使用 LinkedList 实现了 Deque 接口,队列操作更便捷

5.2 区别

不同点 ArrayList LinkedList
存储空间上 物理上一定连续 逻辑上连续,但物理上不一定连续
随机访问 支持,时间复杂度 O (1) 不支持,时间复杂度 O (N)
头插 需要搬移元素,效率低,时间复杂度 O (N) 只需修改引用的指向,时间复杂度 O (1)
插入 空间不够时需要扩容 没有容量的概念
应用场景 元素高效存储 + 频繁访问 任意位置插入和删除频繁

6. LinkedList 的模拟实现

①接口

public interface IList {
    //头插法
    public void addFirst(int data);
    //尾插法
    public void addLast(int data);
    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data);
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key);
    //删除第一次出现关键字为key的节点
    public void remove(int key);
    //删除所有值为key的节点
    public void removeAllKey(int key);
    //得到单链表的长度
    public int size();
    public void clear();
    public void display();
}

②具体方法的实现

public class MyLinkedList implements IList  {

    static class ListNode{//内部类
        public ListNode prev;//结点的前驱
        public ListNode next;//结点的后继
        public int val;

        public ListNode(int val){
            this.val = val;
        }
    }
    //类成员
        public ListNode head;//头结点
        public ListNode last;//尾结点

    //头插法
    @Override
    public void addFirst(int data) {
        ListNode node = new ListNode(data);
        if(head == null){
            head = last = node;
        }else{
            node.next = head;
            head.prev = node;
            head = node;
        }
    }

    //尾插法
    @Override
    public void addLast(int data) {
        ListNode node = new ListNode(data);
        if(head == null){
            head = last = node;
        }else{
            last.next = node;
            node.prev = last;
            last = node;
        }
    }

    //寻找下标为 index 的结点
    private ListNode findIndex(int index){
        ListNode cur = head;
        while (index != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }

    //任意位置插入结点
    @Override
    public void addIndex(int index, int data) {
        int len = size();
        if(index<0||index>size()){
            return;
        }
        if(index == 0){
            addFirst(data);
            return;
        }
        if(index == len){
            addLast(data);
            return;
        }
        ListNode node = new ListNode(data);
        ListNode cur = findIndex(index);
        cur.prev.next = node;
        node.next = cur;
        node.prev = cur.prev;
        cur.prev = node;
    }

    //查找是否包含 key 在链表中
    @Override
    public boolean contains(int key) {
        ListNode cur = head;
        while (cur!=null){
            if(cur.val == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }


    @Override
    public void remove(int key) {
        ListNode cur = head;
        while(cur!=null){
            if(cur.val == key){
                //删除
                if(cur == head){
                    head = head.next;
                    if(head != null) {
                        head.prev = null;
                    }
                }else {
                    cur.prev.next = cur.next;
                    if (cur.next == null) {
                        last = last.prev;
                    } else {
                        cur.next.prev = cur.prev;
                    }
                }
                return;
            }
                cur = cur.next;
        }
    }

    @Override
    public void removeAllKey(int key) {
        ListNode cur = head;
        while(cur!=null){
            if(cur.val == key){
                //删除
                if(cur == head){
                    head = head.next;
                    if(head != null) {
                        head.prev = null;
                    }
                }else {
                    cur.prev.next = cur.next;
                    if (cur.next == null) {
                        last = last.prev;
                    } else {
                        cur.next.prev = cur.prev;
                    }
                }

            }
            cur = cur.next;
        }
    }

    //求链表的长度
    @Override
    public int size() {
        if(head == null){
            return 0;
        }
        ListNode cur = head;
        int count = 0;
        while (cur!=null){
            count++;
            cur = cur.next;
        }
        return count;
    }

    //清空链表
    @Override
    public void clear() {
        ListNode cur = head;
        while (cur!=null){
            ListNode curN = cur.next;
            cur.prev = null;
            cur.next = null;
            cur = curN;
        }
    }

    //打印链表
    @Override
    public void display() {
        ListNode cur = head;
        while (cur!=null){
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }
}

③测试

public class Test {
    public static void main(String[] args) {
        MyLinkedList myLinkedList = new MyLinkedList();
        myLinkedList.addFirst(12);//头插法
        myLinkedList.addLast(22);//尾插法
        myLinkedList.addFirst(45);
        myLinkedList.addFirst(22);
        myLinkedList.display();//22 45 12 22 
        
        myLinkedList.addIndex(2,44);//任意位置插入
        myLinkedList.display();//22 45 44 12 22
        
        myLinkedList.remove(45);//删除元素 45
        myLinkedList.display();//22 44 12 22 
        
        myLinkedList.removeAllKey(22);//删除所有元素 22
        myLinkedList.display();//44 12 
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到