链表进阶2:双向链表的构建

### 链表进阶2:双向链表的构建

  • [@TOC(链表进阶2:双向链表的构建) 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [1.创建链表节点;](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [2.头插法](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [2.尾插](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [3.中间位置插入](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [4.头删](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [5.尾删](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [6.按下标删除](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [7.按值删除](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [8.判断元素是否存在](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [循环遍历即可](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [9.返回存在元素的下标](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [循环遍历即可](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
  • [10.toString方法](#链表进阶2:双向链表的构建 @TOC 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节; 1.创建链表节点; 2.头插法 2.尾插 3.中间位置插入 4.头删 5.尾删 6.按下标删除 7.按值删除 8.判断元素是否存在 循环遍历即可 9.返回存在元素的下标 循环遍历即可 10.toString方法 这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;)
    这一版我没有引入尾部tail,后面会更新单向链表与双向链表引入尾部节点tail的章节;

1.创建链表节点;

这个链表节点与先前的单向链表相比,多了一个prev指向前一个节点;

java 复制代码
class ListNode{
    public int val;
    public ListNode next;
    public ListNode prev;

    public ListNode(int val) {
        this.val = val;
        this.next = null;
        this.prev = null;
    }
}

2.头插法

1)首先要有头节点,判断是否为null,如果是,头节点指向新的节点;

2)新节点指向head,head的前一个节点prev指向新节点;

3)新节点变为头节点;

java 复制代码
public ListNode head = null;
    public void addFirst(int val){
        ListNode newnode = new ListNode(val);
        if(head == null){
            head = newnode;
            return ;
        }
        newnode.next = head;
        head.prev = newnode;
        head = newnode;
    }

2.尾插

1)创建一个尾部节点,头节点;

2)当头节点为空时,全部指向新节点;

3)不为空,尾部插入,还要更新tail尾部

java 复制代码
public void addLast(int val){
        LinkedNode newnode = new LinkedNode(val);
        if(head == null){
            head = newnode;
            return;
        }
        LinkedNode cur = head;
        while(cur.next!=null){
            cur = cur.next;
        }
        cur.next = newnode;
        newnode.prev = cur;
    }

3.中间位置插入

1)首先判断下标,我们需要写链表的尺寸大小;

2)下标为0或者最后调用前面的头插与尾插;

  1. 找出要插入的位置,开始插入
java 复制代码
 private int size(){
        if(head==null){
            return 0;
        }
        int size = 0;
        for(LinkedNode cur = head;cur!=null;cur = cur.next){
            size++;
        }
        return size;
    }
    public void add(int index,int val){
        LinkedNode newnode = new LinkedNode(val);
        int size = size();
        if(index<0||index>size){
            throw new IndexOutOfBoundsException("下标越界");
        }
        if(index==0){
            addFirst(val);
            return;
        }
        if(index==size){
            addLast(val);
            return;
        }
        LinkedNode cur = head;
        for(int i = 0;i<index-1;i++){
            cur = cur.next;
        }
        newnode.next = cur.next;
        cur.next.prev = newnode;
        cur.next = newnode;
        newnode.prev = cur;
    }

4.头删

1)判断是不是头节点head为空或者只有一个节点;

2)更新head

3)注意head的prev指向一定要为null

java 复制代码
public void removeFirst(){
        if(head==null){
            return;
        }
        if(head.next==null){
            head=null;
            return;
        }
        head = head.next;
        head.prev = null;
    }

5.尾删

1)先判断是不是为空,或者只有一个节点

2)找到最后要删除的节点的上一个,让他指向空;

3)删除节点的prev也要指向空;

java 复制代码
public void removeLast(){
        if(head==null){
            return;
        }
        if(head.next==null){
            head=null;
            return;
        }
        LinkedNode tail = head;
        while(tail.next!=null){
            tail = tail.next;
        }
        LinkedNode prev = tail.prev;
        prev.next = null;
        tail.prev=null;
    }

6.按下标删除

1)首先还是要判断下标;

2)下标为0,为尾部特殊处理

3)循环遍历找到要删除的元素;

java 复制代码
 public void remove(int index){
        int size = size();
        if(index<0||index>=size){
            throw new IndexOutOfBoundsException("下标越界");
        }
        if(index==0){
            removeFirst();
            return ;
        }
        if(index==size-1){
            removeLast();
            return;
        }
        LinkedNode toDelete = head;
        for(int i = 0;i<index;i++){
            toDelete = toDelete.next;
        }
        LinkedNode prev = toDelete.prev;
        prev.next = toDelete.next;
        toDelete.next.prev = prev;
        toDelete.next = null;
        toDelete.prev = null;
    }

7.按值删除

1).通过循环遍历,找出要删除的值的节点,直接退出break;

2).判断循环结束是否找到,没找到直接返回;

3).最后考虑删除节点是否为尾部节点;

java 复制代码
    public void removeByvalue(int val){
        if(head==null){
            return;
        }
        if(head.val==val){
     removeFirst();
            return;
        }
        LinkedNode cur = head;
        for(;cur!=null;cur = cur.next){
            if(cur.val==val){
                break;
            }
        }
        if(cur == null){
            return;
        }
        LinkedNode prev = cur.prev;
        LinkedNode next = cur.next;
        prev.next = cur.next;
        if(next!=null){
            next.prev = prev;
        }
        cur.next = null;
        cur.prev = null;
    }

8.判断元素是否存在

循环遍历即可

java 复制代码
    public boolean contains(int val) {
        if (head == null) {
            return false;
        }
        for (LinkedNode cur = head; cur != null;cur = cur.next ) {
if(cur.val==val){
    return true;
}
        }
        return false;
    }

9.返回存在元素的下标

循环遍历即可

java 复制代码
    public int indexOf(int val) {
        int i = 0;
        for (LinkedNode cur = head; cur != null; cur = cur.next, i++) {
            if (cur.val == val) {
                return i;
            }
        }
        return -1;
    }

10.toString方法

java 复制代码
public String toString(){
        if(head==null){
            return null;
        }
        StringBuilder str = new StringBuilder();
        for(LinkedNode cur = head;cur!=null;cur = cur.next){
            str.append(cur.val+"");
            if(cur.next!=null){
                str.append(", ");
            }
        }
        LinkedNode tail = head;
        while(tail.next!=null){
            tail = tail.next;
        }
        str.append("||");
        for(LinkedNode cur = tail;cur!=null;cur = cur.prev){
            str.append(cur.val+"");
            if(cur.prev!=null){
                str.append(", ");
            }
        }
        return str.toString();
}
java 复制代码
public class TestToString {
    private static int pass = 0, fail = 0;
    private static void check(String name, String expected, String actual) {
        if (expected == null ? actual == null : expected.equals(actual)) {
            pass++;
            System.out.println("[PASS] " + name + "  -> \"" + actual + "\"");
        } else {
            fail++;
            System.out.println("[FAIL] " + name);
            System.out.println("       expected: \"" + expected + "\"");
            System.out.println("       actual  : \"" + actual + "\"");
        }
    }

    public static void main(String[] args) {
        MyDLinkedList empty = new MyDLinkedList();
        check("空链表", "", empty.toString());

        MyDLinkedList one = new MyDLinkedList();
        one.addFirst(1);
        check("单节点 [1]", "1||1", one.toString());

        MyDLinkedList multi = new MyDLinkedList();
        multi.addLast(1);
        multi.addLast(2);
        multi.addLast(3);
        check("多节点 [1,2,3]", "1, 2, 3||3, 2, 1", multi.toString());

        MyDLinkedList afterHead = new MyDLinkedList();
        afterHead.addLast(1);
        afterHead.addLast(2);
        afterHead.addLast(3);
        afterHead.removeFirst();
        check("头删后 [2,3]", "2, 3||3, 2", afterHead.toString());

        MyDLinkedList afterTail = new MyDLinkedList();
        afterTail.addLast(1);
        afterTail.addLast(2);
        afterTail.addLast(3);
        afterTail.removeLast();
        check("尾删后 [1,2]", "1, 2||2, 1", afterTail.toString());

        System.out.println("\n通过 " + pass + ",失败 " + fail);
    }
}
相关推荐
DianSan_ERP2 小时前
多平台订单自动下载与回传的技术实现:从消息推送到状态闭环引言
java·linux·服务器·前端·网络·架构·自动化
Joe_Wang52 小时前
【从0到1学习JVM · 13】点进JDK源码只有一个分号?搞懂本地方法栈与JNI机制
java·jvm·学习·本地方法栈
AI 算法大模型备案~当当2 小时前
各地备案数量怎么看:一份属地公告的认读与台账方法
java·数据库·人工智能
智鸟科技GemeOpen开发者智能设备2 小时前
GemeOpen 智能音箱 GSSM0B - 播放控制(Java示例)
java·开发语言·智能音箱
今天的砖头有点烫手啊2 小时前
Java IO/NIO/AIO 演进:从 BIO 到 Netty 的底层逻辑
java·jvm·nio
梦帮科技2 小时前
量子张量网络破局大模型:从矩阵乘积态 (MPS) 到张量列 (TT-SVD) 低秩收缩全推导
网络·数据结构·数据库·线性代数·矩阵·架构·模拟退火算法
谢亮_vipxieliang3 小时前
Java 21 新特性实战:Record、Sealed、模式匹配
java·开发语言
霸道流氓气质3 小时前
LLM 应用限流与熔断机制完全指南:从多层防护架构到Java生产级弹性实战
java·开发语言·架构
LOVE️YOU3 小时前
Python 数据结构的本质:位置、对象引用、Hash 与可变性
数据结构·python·哈希算法