LinkedList概念+MyLinkedList的实现

文章目录


LinkedList笔记


一、 LinkedList

1.概念

LinkedList的底层是一个双向链表

  • 在插入和删除时,不用挪动元素
  • 在获取尾部结点时,不需要遍历获取,直接利用last结点

2.LinkedList的构造方法

  • 分为无参构造和有参构造

有参:使用其他集合容器中元素构造List

在构造LinkedList的时候,传递的参数的类型要满足指定泛型的上界,同时要实现Collection接口

3.LinkedList的遍历

分别用重写的print方法、foreach、迭代器进行遍历

java 复制代码
 public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("hello");
        linkedList.add("world");
        linkedList.add("!");
        linkedList.add("?");
        linkedList.add("|");
        System.out.println(linkedList);
        System.out.println("-----------");
        for (String x:linkedList) {
            System.out.print(x+" ");
        }
        System.out.println();
        System.out.println("-----------");
        //使用迭代器遍历-正向遍历
        ListIterator<String> it = linkedList.listIterator();
        while (it.hasNext()){
            System.out.print(it.next()+" ");
        }
        System.out.println();
        System.out.println("===========");

        ListIterator<String> rit = linkedList.listIterator(linkedList.size());
        while (rit.hasPrevious()){
            System.out.print(rit.previous()+" ");
        }

        //使用迭代器遍历-反向遍历
    }

二、MyLinkedList的实现

1.定义内部类

与单链表不同的是,双链表的结点新增了prev域

java 复制代码
public class MyLinkedList {
    static class ListNode{
        public int val;
        public ListNode prev;//前驱
        public ListNode next;//后继

        public ListNode(int val) {//构造方法
            this.val = val;
        }
    }
    public ListNode head;//定义头结点
    public ListNode last;//定义尾结点

1.在内部类中定义结点的元素

2.定义构造器

3.创建头/尾结点

2.打印链表、求链表长度、判断是否包含关键字

与单链表的形式相同

java 复制代码
 public void  disPlay(){
        ListNode cur = head;
        while (cur!=null){ 
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

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

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

3. 头插法和尾插法

java 复制代码
    /**
     * 头插法
     * o(1)
     * @param data
     */
    public void addFirst(int data){
        ListNode node = new ListNode(data);
        if (head ==null){
            head = node;
            last = node;
        }else {
            node.next = head;
            head.prev = node;
            head = node;//头结点前移
        }
    }

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

因为尾插的时候有last结点,不用进行尾结点的遍历查找

所以双链表尾插的时间复杂度是 o(1)

4.在任意位置插入

java 复制代码
  public void addIndex(int index, int data) {

        if (index < 0 || index > size()) {//判断索引是否超出
           return;
        }
        if (index == 0) {//利用头插
            addFirst(data);
            return;
        }
        if (index == size()) {//利用尾插
            addLast(data);
            return;
        }
        ListNode node = new ListNode(data);
        ListNode cur = head;
        while (index!=0){//找到索引的位置
            cur = cur.next;
            index--;
        }
        node.next = cur;
        cur.prev.next = node;
        node.prev = cur.prev;
        cur.prev = node;
    }

1.先判断索引下标是否溢出

2.如果索引是开头或者末尾的位置,调用写好的头插法和尾插法

3.通过遍历找到索引的位置cur

4.将cur插入链表中

  • 先改变node的next域,
  • 将node与cur相连 将cur的前驱的next域,改为node,
  • 将node与cur的前一个结点相连
  • 将node前驱改为cur前驱的地址 将cur的前驱改为node的地址值

5.删除结点

java 复制代码
    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;//head的前驱置为空
                    }

                } else {//删除中间或者尾部
                    cur.prev.next = cur.next;
                    if (cur == last) {//如果是尾部
                        last = last.prev;
                    } else {//删除的是中间
                        cur.next.prev = cur.prev;
                    }
                }
                return;
            }
            cur = cur.next;
        }
    }

1.通过遍历找到值等于key的结点

2.如果要删的是头结点,头结点向后移动一位。如果移动后的头结点不为空,将此时头结点的前驱置为空

3.如果要删除的cur是尾结点,将cur前驱的地址值指向cur的下一个地址,将last向前移动一位

4.如果要删除的是中间结点,将cur前驱的地址值指向cur的下一个地址,将cur后继的前驱指向cur的前驱

6.清空链表

java 复制代码
 public void clear() {
        ListNode cur = head;
        while (cur != null) {
            ListNode curNext = cur.next;
            cur.next = null;
            cur.prev = null;
            cur = curNext;
        }
        head = null;
        last = null;
    }

1.遍历链表,用curNext记录cur的下一个结点

2.将cur的前驱和后继置为null

3.将头结点和尾结点置为空。

点击移步博客主页,欢迎光临~

相关推荐
sugar__salt3 小时前
从栈队列数据结构到JS原型面向对象全解
前端·javascript·数据结构
三品吉他手会点灯4 小时前
C语言学习笔记 - 43.运算符与表达式 - 运算符1 - 运算符的分类和简单介绍
c语言·笔记·学习·算法
疯狂打码的少年4 小时前
中断处理过程与中断优先级
笔记
心之伊始4 小时前
Java 后端接入大模型:从 Token、并发到推理成本的完整估算方法
java·spring boot·性能优化·大模型·llm
likerhood4 小时前
WSL 下安装 Miniconda 笔记
笔记·wsl
BlackTurn5 小时前
技术经理投标
java
YG亲测源码屋5 小时前
java配置环境变量、jdk环境变量配置、java环境变量设置方法
java·开发语言
MIUMIUKK5 小时前
从语法层面,看懂 Python 的特殊处
java·开发语言·python
hujinyuan201605 小时前
2026年3月 中国电子学会青少年软件编程(Python)三级考试试卷 真题及答案
java·python·算法
froyoisle5 小时前
CSP-J 历年复赛 T1 及解析(2019~2025)
数据结构·c++·算法·csp-j·csp·算法竞赛·信息学