LinkedList与链表

发布于:2025-03-21 ⋅ 阅读:(15) ⋅ 点赞:(0)

ArrayList的缺陷

        在上一篇博客中,小编已经较为详细得给大家介绍了ArrayList这个结构了。但是ArrayList存在一些缺陷:由于其底层是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。

        因此:java集合中又引入了LinkedList,即链表结构


链表

链表的概念及结构

        链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

双向 单向、带头 不带头、循环 不循环

我们主要学习:单向不带头非循环、双向不带头非循环


链表的实现

这里就是自己在写一些链表的方法的时候,自己动手实现一下,感受一下这个链表的内部结构。

代码展示:

package LinkedList;

public class MySingleList {

    // 这里提供一个内部类
    static class ListNode{
        public int val;  //节点的值域
        public ListNode next; // 下一个节点的地址

        // 这里提供一个构造方法
        public ListNode(int val){
            this.val = val;
        }
    }

    public ListNode head;  // 表示当前链表的头节点

    /**
     * 提供一个方法进行链表的初始化
     */
    public void createList(){
        ListNode node1 = new ListNode(12);
        ListNode node2 = new ListNode(34);
        ListNode node3 = new ListNode(45);
        ListNode node4 = new ListNode(56);
        ListNode node5 = new ListNode(67);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        this.head = node1;
    }





    /**
     * 下面是一个方法的实现【其实就是增删改查】
     */

    //头插法
    public void addFirst(int data){
        ListNode node = new ListNode(data);
//        // 要考虑列表为空的情况
//        if (head == null){
//            head = node;
//        }
        node.next = head;
        head = node;
    }

    //尾插法
    public void addLast(int data){
        ListNode node = new ListNode(data);
        // 要考虑列表为空的情况
        if (head == null){
            head = node;
            return;
        }
        ListNode curhead = head;
        while (curhead.next != null){
            curhead = curhead.next;
        }
        curhead.next = node;
    }

    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        ListNode curhead = head;
        if (index < 0 || index > size()) {
            System.out.println("您提供的index不合法!");
            return;
        }
        ListNode node = new ListNode(data);
        // 处理空链表情况
        if (head == null) {
            if (index == 0) {
                head = node;
                System.out.println("您的列表为空! 直接插入到第一个位置");
            } else {
                System.out.println("链表为空,index > 0 无效!");
            }
            return;
        }
        if (index == 0){
            addFirst(data);
            return;
        }
        for (int i = 0; i < index-1; i++) {
            curhead = curhead.next;
        }
        node.next = curhead.next;
        curhead.next = node;
    }

    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        // 就默认列表为空就是没有
        ListNode curhead = head;
        while (curhead!=null){
            if (curhead.val == key){
                return true;
            }
            curhead = curhead.next;
        }
        return false;
    }


    //删除第一次出现关键字为key的节点
    public void remove(int key){
        if (head == null) { // 处理空链表
            return;
        }

        // 处理删除头节点的情况
        if (head.val == key) {
            head = head.next;
            return;
        }

        ListNode cur = head;
        while (cur.next != null) { // 遍历链表
            if (cur.next.val == key) {
                cur.next = cur.next.next; // 删除当前匹配的节点
                return; // 只删除第一个匹配项
            }
            cur = cur.next;
        }
    }



    //删除所有值为key的节点
    public void removeAllKey(int key){
        if (head == null) { // 处理空链表
            return;
        }

        // 处理删除所有头节点为 key 的情况
        while (head != null && head.val == key) {
            head = head.next;
        }

        // 处理删除中间或尾部的 key
        ListNode cur = head;
        while (cur != null && cur.next != null) {
            if (cur.next.val == key) {
                cur.next = cur.next.next; // 删除当前匹配的节点
            } else {
                cur = cur.next; // 只有当 cur.next 不是 key 时才移动
            }
        }
    }


    //得到单链表的长度
    public int size(){
        int ListSize = 0;
        ListNode curhead = head;
        // 来一个语句判断一下链表是否为空
        while (curhead != null){
            ListSize++;
            curhead = curhead.next;
        }
        return ListSize;  // 如果长度为0【即为空列表即返回这个,告诉用户这是一个空的列表】
    }


    // 清空所有链表
    public void clear() {
        this.head = null;
    }


    // 展示所有列表的数据
    public void display() {
        // 进来先判断一下链表是否为空
        if (head == null){
            System.out.println("该列表为空!");
            return;
        }
        ListNode curhead = head;
        while (curhead!=null){
            System.out.print(curhead.val+" ");
            curhead = curhead.next;
        }
        System.out.println();
    }


}

注:小编这里的代码并不是最优的,只是起一个参考的作用。

测试代码:

package LinkedList;

public class Test {
    public static void main(String[] args) {
        MySingleList mySingleList = new MySingleList();
        mySingleList.createList();  // 先把这个初始列表创建出来

        // 将列表全部展现出来
        mySingleList.display();

        // 得到单链表的长度
        int length = mySingleList.size();
        System.out.println("单链表的长度为:"+length);

        // 进行头插
        mySingleList.addFirst(99);
        mySingleList.display();

        // 进行尾插
        mySingleList.addLast(520);
        mySingleList.display();

        // 任意位置插入
        mySingleList.addIndex(0, 1314);
        mySingleList.display();
        mySingleList.addIndex(8, 8989);
        mySingleList.display();

        // 查找是否包含关键字key是否在单链表当中
        boolean result = mySingleList.contains(99);
        if (result == true){
            System.out.println("链表中存在这个值!");
        }else {
            System.out.println("不好意思!链表中不存在这个值!");
        }

        // 删除第一次出现关键字为key的节点
        mySingleList.addFirst(99);
        mySingleList.addFirst(99);
        mySingleList.addLast(99);
        mySingleList.display();
//        mySingleList.remove(99);
//        mySingleList.display();

        //删除所有值为key的节点
        mySingleList.removeAllKey(99);
        mySingleList.display();
    }
}

测试代码不唯一,这里的测试代码也只是起一个参考作用【小编这里的方法代码和测试代码是放到了同一个包里】,大家的代码如果位置不一致,要注意限定修饰符的使用。


链表面试题

1. 删除链表中等于给定值 val 的所有节点。203. 移除链表元素 - 力扣(LeetCode)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if (head == null) { // 处理空链表
            return null;
        }

        // 处理删除所有头节点为 key 的情况
        while (head != null && head.val == val) {
            head = head.next;
        }

        // 处理删除中间或尾部的 key
        ListNode cur = head;
        while (cur != null && cur.next != null) {
            if (cur.next.val == val) {
                cur.next = cur.next.next; // 删除当前匹配的节点
            } else {
                cur = cur.next; // 只有当 cur.next 不是 key 时才移动
            }
        }
        return head;
    }
}

2. 反转一个单链表.206. 反转链表 - 力扣(LeetCode)

class Solution {
   public ListNode reverseList(ListNode head) {
        ListNode cur = head;
        ListNode pre = null; // 关键修改:pre 应该从 null 开始
        while (cur != null) {
            ListNode next = cur.next; // 先保存下一个节点
            cur.next = pre; // 反转当前节点的指向
            pre = cur; // 移动 pre 指针
            cur = next; // 继续遍历
        }
        return pre; // 反转后,pre 是新的头节点
    }
}

3.给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。876. 链表的中间结点 - 力扣(LeetCode)

方法1:算数组长度

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public int size(ListNode head){
        int ListSize = 0;
        ListNode curhead = head;
        // 来一个语句判断一下链表是否为空
        while (curhead != null){
            ListSize++;
            curhead = curhead.next;
        }
        return ListSize;  // 如果长度为0【即为空列表即返回这个,告诉用户这是一个空的列表】
    }
    public ListNode middleNode(ListNode head) {
        ListNode cur = head;
        int index = size(head)/2;
        for(int i = 0; i < index; i++){
            cur = cur.next;
        }
        head = cur;
        return head;
    }
}

方法2:快慢指针

快指针都两步,慢指针走一步;当快指针走到末尾的时候,慢指针刚好走到中间位置;

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
}

这个代码需要注意的点就是“空指针异常”,在判断循环条件的时候需要多加注意这个逻辑问题。


4. 输入一个链表,输出该链表中倒数第k个结点。

方法一:循环遍历,找到下标

 // 1.输入一个链表,输出该链表中倒数第k个结点
    public int return_val(int k){
        ListNode cur = head;
        for (int i = 0; i < size()-k; i++) {
            cur = cur.next;
        }
        return cur.val;
    }

方法2:快慢指针法

fast先走k-1步;fast和slow再同时走,当fast到终点的时候,slow就刚好到倒数第K个位置。

   public ListNode FindthToTail(int k){
        if (k <= 0 || k > size() || head == null){
            System.out.println("您提供的下标有误!");
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        for (int i = 0; i < k-1; i++) {
            fast = fast.next;
        }
        while (fast.next!=null){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }

5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。21. 合并两个有序链表 - 力扣(LeetCode)

代码示例:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode headA = list1;
        ListNode headB = list2;
        ListNode nh = new ListNode();
        ListNode th = nh;
        while(headA!=null && headB!=null){
            if(headA.val > headB.val){
                th.next = headB;
                th = th.next;
                headB = headB.next;
            }else{
                th.next = headA;
                th = th.next;
                headA = headA.next;
            }
        }
        if(headA!=null){
            th.next = headA;
        }else{
            th.next = headB;
        }
        return nh.next;
    }
}

6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。链表分割_牛客题霸_牛客网

代码示例:

import java.util.*;

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Partition {
    public ListNode partition(ListNode pHead, int x) {
        // write code here
        ListNode bs = null;
        ListNode be = null;
        ListNode as = null;
        ListNode ae = null;
        ListNode cur = pHead;
        while(cur != null){
            // 这是第一次插入的情况
            if(cur.val<x){
                if(be == null){
                  be = bs = cur;
                }else{
                  be.next = cur;
                  be = be.next;
                }
            }else{
                 if(ae == null){
                    ae = as = cur;
                 }else{
                   ae.next = cur;
                   ae = ae.next;
                 }
            }
    
           
            cur = cur.next;
        }
        // 第一个段没有数据
        if(be == null){
            return as;
        }
        be.next = as;
        // 防止最大的数据不是最后一个
        if(as!=null){
            ae.next = null; 
        }
        return bs;
    }
}

注:在写这个代码的时候,需要注意很多细节类的东西,尤其是一些极端情况,需要多画图看。


7. 链表的回文结构。链表的回文结构_牛客题霸_牛客网

三个步骤:

1.找到链表的中间节点

2.翻转中间节点以后的链表

3.从前/从后开始比较

代码示例:

import java.util.*;

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class PalindromeList {
    public boolean chkPalindrome(ListNode A) {
        // 1.找到中间位置
        // write code here
        ListNode fast = A;
        ListNode slow = A;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        // 2.开始反转
        ListNode cur = slow.next;
        ListNode curNext = null;
        while(cur!=null){
            curNext = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curNext;
        }
        // 3.开始往前往后走
        while(A!=slow){
            if(A.val != slow.val){
                return false;
            }
            if(A.next == slow){
                return true;
            }
            A = A.next;
            slow = slow.next;
        }
        return true;
    }
}

注:上述代码就是前面代码的综合,当我们在写代码的时候,应该考虑到奇数和偶数的不同情况。


8. 输入两个链表,找出它们的第一个公共结点。160. 相交链表 - 力扣(LeetCode)

核心问题:

1.相交是Y字型

2.两个链表长度不一样主要在相交之前

3.可以先让最长链表引用先走他们的差值步

方法1:这个是小编自己画图想出来的方法

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    // 定义一个方法来求列表的长度
    public int size(ListNode head){
        int ListSize = 0;
        ListNode curhead = head;
        // 来一个语句判断一下链表是否为空
        while (curhead != null){
            ListSize++;
            curhead = curhead.next;
        }
        return ListSize;  // 如果长度为0【即为空列表即返回这个,告诉用户这是一个空的列表】
    }
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int ListSizeA = size(headA);  // 这是列表A的长度
        int ListSizeB = size(headB);  // 这是列表B的长度

        // 下面这一步是计算差值,并且先让长的走差值步
        int Difference = 0;
        ListNode curA = headA;
        ListNode curB = headB;
        if(ListSizeA > ListSizeB){
            Difference = ListSizeA - ListSizeB;
            for(int i = 0;i < Difference;i++){
                curA = curA.next;  // 如果列表a长,则先让curA先走差值步
            }
        }else{
            Difference = ListSizeB - ListSizeA;
            for(int i = 0;i < Difference;i++){
                curB = curB.next;  // 如果列表b长,则先让curB先走差值步
            }
        }

        // 接下来就是一块走了
        while(curA != null && curB != null){
            if(curA==curB){
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }
}

方法2:由大家补充~


9. 给定一个链表,判断链表中是否有环。 141. 环形链表 - 力扣(LeetCode)

新奇思路:有点类似于操场跑步绕圈,当一个人跑得慢,一个人跑得快,过了一段时间后就会相遇【即有环一定会相遇】

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head.next;

        while (fast != null && fast.next != null) {
            if (fast == slow) {
                return true;  // 快慢指针相遇,说明有环
            }
            fast = fast.next.next; // fast 每次走两步
            slow = slow.next;
        }
        return false;
    }
}

10. 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL.142. 环形链表 II - 力扣(LeetCode)

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        // 当我这个列表一个元素都没有的情况下
        if(head == null){
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;  // 快的一下子走两步
            slow = slow.next; // 慢的一下子走一步
            if(fast == slow){
                break;  // 退出循环
            }
        }
        if(fast == null || fast.next == null){
            return null;  // 没有环
        }
        fast = head;
        while(fast != slow){
            fast = fast.next;
            slow = slow.next;
        }
        return fast;
    }
}

如上述代码中,我们还是依旧是使用快慢指针来进行思路的讲解。所以在链表中,我们要善于使用快慢指针,还同时要注意null的循环条件,是本身不为空,还是下一个不为空。


LinkedList的模拟实现

底层实现的一些底层模拟方法代码:

package double_LinkedList;

public class My_double_LinkedList {
    static class ListNode{
        public int val;
        public ListNode pre;  // 这个是节点的前驱
        public ListNode next; // 这个是节点的后继

        // 这里提供一个内部方法
        public ListNode(int val){
            this.val = val;
        }
    }
    // 定义一个头节点
    public ListNode head;
    public ListNode last;  // 进行尾插法就不需要循环列表了



    /**
     * 接下来就是一些模拟实现的方法
     */


    //头插法
    public void addFirst(int data){
        ListNode node = new ListNode(data);  // 先创建一个节点
        // 如果链表为空
        if (head == null){
            head = node;  // 此时这个节点就是头节点
            last = node;
            return;
        }
        // 如果这个链表不为空
        node.next = head;
        head.pre = node;
        head = node;
    }


    //尾插法
    public void addLast(int data){
        ListNode node = new ListNode(data);
        if (head == null){
            head = node;
            last = node;
            return;  // 一定要记得结果,不然就会执行下面的代码
        }
//        ListNode cur = head;
        // 这个循环是让cur走到最后一个节点
//        while (cur.next!=null){
//            cur = cur.next;
//        }
//        cur.next = node;
//        node.pre = cur;
        last.next = node;
        node.pre = last;
        last = node;

    }



    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        ListNode node = new ListNode(data);
        if (index < 0 || index > size() ){
            System.out.println("您提供的下标不合法!");
            return;
        }
        if(head == null){
            if (index==0){
                head = node;
            }else {
                System.out.println("您提供的下标不合法!");
            }
        }else {    // 就是head不为空的情况
            // 头插法
            if (index == 0){
                addFirst(data);
                return;
            }
            // 尾插法
            if (index == size()){
                addLast(data);
                return;
            }
//            ListNode curNext = null;
            ListNode cur = head;
            for (int i = 0; i < index; i++) {
                cur = cur.next;  // cur一直前进到插入位置的前一个
            }
            node.next = cur;
            node.pre = cur.pre;
            cur.pre.next = node;
            cur.pre = node;
        }
    }



    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        // 要考虑空链表得情况
        if (head == null){
            return false;
        }
        // 当非空链表的时候
        ListNode cur = head;
        while (cur.next != null){
            if (cur.val == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }


    //删除第一次出现关键字为key的节点
    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.pre = null;
                   }else {
                       last = null;
                   }
               }else {
                   // 删除中间节点和末尾节点
                   if (cur.next != null){
                       // 删除中间节点
                       cur.pre.next = cur.next;
                       cur.next.pre = cur.pre;
                   }else {
                       //删除尾巴节点
                       cur.pre.next = cur.next;
                       last = last.pre;
                   }
               }
               return;
           }else {
               cur = cur.next;
           }
       }
    }




    //删除所有值为key的节点
    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.pre = null;
                    } else {
                        last = null;
                    }
                } else {
                    // 删除中间节点和末尾节点
                    if (cur.next != null) {
                        // 删除中间节点
                        cur.pre.next = cur.next;
                        cur.next.pre = cur.pre;
                    } else {
                        //删除尾巴节点
                        cur.pre.next = cur.next;
                        last = last.pre;
                    }
                }
            }
            cur = cur.next;
        }

    }






    //得到单链表的长度
    public int size(){
        int usedSize = 0;
        ListNode cur = head;
        while (cur!=null){
            usedSize++;
            cur = cur.next;
        }
        return usedSize;
    }





    // 打印列表里面所有的值
    public void display(){
        // 第一步还是要判断一下链表是否为空
        if (head == null){
            return;
        }
        ListNode cur = head;
        while (cur != null){
            System.out.print(cur.val + " ");
            cur = cur.next;  // 要让节点往后走
        }
        System.out.println();  // 打印一个空格使其更美观
    }


    // 清楚列表里面所有的值
    public void clear(){
        ListNode cur = head;
        while (cur != null){
            ListNode curNext = cur.next;
            cur.pre = null;
            cur.next = null;
            cur = curNext;
        }
        head = null;  // 手动置空
        last = null;
    }
}

测试代码:

package double_LinkedList;

public class Test {
    public static void main(String[] args) {
        My_double_LinkedList myDoubleLinkedList = new My_double_LinkedList();
        /**
         * 下面是一些方法的测试
         */

        //  1.头插法 + 打印链表里面的所有元素
        myDoubleLinkedList.addFirst(56);
        myDoubleLinkedList.addFirst(45);
        myDoubleLinkedList.addFirst(34);
        myDoubleLinkedList.addFirst(23);
        myDoubleLinkedList.addFirst(12);
        myDoubleLinkedList.display();


        // 2.尾插法 + 打印链表里面的所有元素
        myDoubleLinkedList.addLast(99);
        myDoubleLinkedList.addLast(1314);
        myDoubleLinkedList.display();

        // 3.链表的长度
        int lenth = myDoubleLinkedList.size();
        System.out.println("目前链表得长度是:" + lenth);
        System.out.println("==========================");

        // 4.任意位置插入
        myDoubleLinkedList.addIndex(0, 11);
        myDoubleLinkedList.addIndex(6, 888);
        myDoubleLinkedList.addIndex(3, 666);
        myDoubleLinkedList.display();
        myDoubleLinkedList.addIndex(13, 7777);
        System.out.println("===========================");

        // 5.找是否包含关键字key是否在单链表当中
        boolean result1 = myDoubleLinkedList.contains(888);
        System.out.println(result1);
        boolean result2 = myDoubleLinkedList.contains(5555);
        System.out.println(result2);
        System.out.println("===========================");


        // 6.删除第一次出现关键字为key的节点
        myDoubleLinkedList.display();
        myDoubleLinkedList.remove(1314);   // 删除最后一个
        myDoubleLinkedList.display();
        myDoubleLinkedList.remove(11);  // 删除第一个
        myDoubleLinkedList.display();
        myDoubleLinkedList.remove(666);  // 删除中间数值
        myDoubleLinkedList.display();
        System.out.println("===========================");

        // 7. 删除所有值为key的节点
        myDoubleLinkedList.addFirst(1111);
        myDoubleLinkedList.addFirst(1111);
        myDoubleLinkedList.addFirst(1111);
        myDoubleLinkedList.addIndex(4, 1111);
        myDoubleLinkedList.addLast(1111);
        myDoubleLinkedList.addLast(1111);
        myDoubleLinkedList.display();
        myDoubleLinkedList.removeAllKey(1111);
        myDoubleLinkedList.display();
        System.out.println("==========================");


    }
}

LinkedList的使用

什么是LinkedList

        LinkedList的底层是双向链表结构(链表后面介绍),由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。

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


LinkedList的使用

举个例子:

List<Integer> list = new LinkedList<>();

其他常用方法:

ArrayList和LinkedList的区别

一般从存储和操作两方面进行比较

补充:那顺序表链表的区别是什么?