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.将头结点和尾结点置为空。

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

相关推荐
wm104310 分钟前
java web springboot
java·spring boot·后端
smile-yan12 分钟前
Provides transitive vulnerable dependency maven 提示依赖存在漏洞问题的解决方法
java·maven
老马啸西风13 分钟前
NLP 中文拼写检测纠正论文-01-介绍了SIGHAN 2015 包括任务描述,数据准备, 绩效指标和评估结果
java
m0_7482567816 分钟前
WebGIS实战开源项目:智慧机场三维可视化(学习笔记)
笔记·学习·开源
Earnest~16 分钟前
Maven极简安装&配置-241223
java·maven
皮蛋很白19 分钟前
Maven 环境变量 MAVEN_HOME 和 M2_HOME 区别以及 IDEA 修改 Maven repository 路径全局
java·maven·intellij-idea
红色的山茶花20 分钟前
YOLOv9-0.1部分代码阅读笔记-loss.py
笔记
青年有志21 分钟前
JavaWeb(一) | 基本概念(web服务器、Tomcat、HTTP、Maven)、Servlet 简介
java·web
上海研博数据25 分钟前
flink+kafka实现流数据处理学习
java
KpLn_HJL26 分钟前
leetcode - 2139. Minimum Moves to Reach Target Score
java·数据结构·leetcode