Java数据结构(八):双链表的实现

🌸雨落在了我的手上:个人主页

🐟个人仓库:Gitee仓库

❄️个人专栏:<<JaveSe>> <<C语言>> <<C语言数据结构>>**

🔥🔥🔥 人生格言:无人扶我青云志,我自踏雪至山巅

🎬 博主简介:


目录

一:双链表的前期准备

二:双链表的实现

1.头插

2.尾插

3.指定下标插入

4.通过值查找

5.查找并且返回其对应下标

6.头删

7.尾删

8.通过下标删除

9.指定值删除

10.修改节点

三:代码解析

1.中间插入

2.中间删除


内容大纲:

本文介绍了双链表的基本实现方法,重点讲解了双链表的增删改查操作。首先定义了双链表节点类DLikedNode和双链表类MyDLikedList,包含前驱指针prev和后继指针next。文章详细演示了10种核心操作:头插、尾插、指定位置插入、值查找、下标查找、头删、尾删、指定位置删除、值删除以及修改节点。其中特别解析了中间插入和删除的操作原理,通过修改前后节点的指针关系实现数据操作。所有方法都考虑了空链表、单节点等特殊情况,并实现了双向打印功能验证链表结构。双链表的实现与单链表类似,主要区别在于多维护了一个前驱指针。


一:双链表的前期准备

前面的文章我们都已经了解了线性表,而线性表又包括了顺序表和链表,然后链表又包括了单链表和双链表,前面我们都已经写过了,这里我们再写一个双链表,本质也是增删改查,和单链表几乎一模一样,只是多了一个prev罢了!!!

这里我们创建一个类DLikedNode,用来代表我们的节点

java 复制代码
//代表节点
class DLikedNode{
    public int val;
    public DLikedNode prev;
    public DLikedNode next;

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

再创建一个类MyDLikedList,表示我们整个双链表,还有一个头节点,方便我们书写代

java 复制代码
public class MyDLikedList {
//代表头节点
    private DLikedNode head;
增
删
改
查
....
}

书写一个toString方法,来方便我们打印内容,这里我们还格外加了一个反向打印内容,方便我们验证双链表

java 复制代码
    //toString方法,并且可以方向打印结果
    @Override
    public String toString(){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("[");

        //这里单独定义一个tail尾指向,方便我们后续的反向打印
        DLikedNode tail=null;

        //进入循环,开始打印内容
        for (DLikedNode cur=head;cur!=null;cur=cur.next){
            //一开始让cur和tail指向开头,循环完之后,tail和cur就都指向最后一个了
            tail=cur;

            stringBuilder.append(cur.val);
            if (cur.next!=null){
                stringBuilder.append(",");
            }
        }
        stringBuilder.append("] | [");

        //此时cur和tail都指向尾部
        //进入循环,开始反向打印
        for (DLikedNode cur=tail;cur!=null;cur=cur.prev){
            stringBuilder.append(cur.val);
            if (cur.prev!=null){
                stringBuilder.append(",");
            }
        }

        stringBuilder.append("]");
        return stringBuilder.toString();
    }

获取有效元素的方法

java 复制代码
    //获取有效元素
    public int size(){
        int size=0;
        for (DLikedNode cur=head;cur!=null;cur=cur.next){
            size++;
        }
        return size;
    }

二:双链表的实现

1.头插

java 复制代码
    public void addFirst(int val){
        DLikedNode newNode = new DLikedNode(val);
        //空情况
        if (head==null){
            head=newNode;
            return;
        }
        //非空情况
        newNode.next=head;
        head.prev=newNode;
        head=newNode;
    }

2.尾插

java 复制代码
    //2.尾插
    public void addLast(int val){
        DLikedNode newNode=new DLikedNode(val);
        //空情况
        if (head==null){
            head=newNode;
            return;
        }
        //非空情况
        DLikedNode cur=head;
        while (cur.next!=null){
            cur=cur.next;
        }
        //此时cur指向最后一个节点
        cur.next=newNode;
        newNode.prev=cur;
    }

3.指定下标插入

java 复制代码
    //3.指定下标插入
    public void add(int index,int val){
        DLikedNode newNode = new DLikedNode(val);

        //避免重复调用size
        int size=size();

        //异常情况,下标不正确
        if (index<0||index>size){
            throw new IndexOutOfBoundsException("下标越界");
        }

        //下标为0,即头插
        if (index==0){
            addFirst(val);
            return;
        }

        //下标为size,即尾插
        if (index==size){
            addLast(val);
            return;
        }

        //一般情况
        //先找到要插入位置的前一个节点
        DLikedNode cur =head;
        for (int i =0;i<index-1;i++){
            cur=cur.next;
        }
        //此时cur已经指向前一个节点
        //我们再定义一个next
        DLikedNode next = cur.next;

        //核心代码
        cur.next=newNode;
        newNode.prev=cur;
        newNode.next=next;
        next.prev=newNode;
    }

4.通过值查找

java 复制代码
    //4.值查找
    public boolean contains(int value){
        for (DLikedNode cur=head;cur!=null;cur=cur.next){
            if (cur.val==value){
                return true;
            }
        }
        //此时没有找到
        return false;
    }

5.查找并且返回其对应下标

java 复制代码
    //5.查找,返回下标
    public int indexOf(int value){
        int index = 0;
        for (DLikedNode cur =head;cur!=null;cur=cur.next){
            if (cur.val==value){
                return index;
            }
            index++;
        }
        //此时没有找到,返回-1
        return -1;
    }

6.头删

java 复制代码
    //6.头删
    public void removeFirst(){
        //空情况
        if (head==null){
            return;
        }

        //只有一个节点的情况
        if (head.next==null){
            head=null;
            return;
        }

        //一般情况
        head=head.next;
        head.prev=null;
    }

7.尾删

java 复制代码
    //7.尾删
    public void removeLast(){
        //空情况
        if (head==null){
            return;
        }

        //只有一个节点情况
        if (head.next==null){
            head=null;
            return;
        }

        //一般情况
        //要先找到要删除节点的前一节点
        DLikedNode tail=head;
        while (tail.next!=null){
            tail=tail.next;
        }
        DLikedNode prev= tail.prev;

        //此时已经指向前一节点
        prev.next=null;
    }

8.通过下标删除

java 复制代码
    //8.通过下标删除
    public void remove(int index){
        int size =size();
        //异常情况
        if (index<0||index>=size){
            throw new IndexOutOfBoundsException("下标越界");
        }

        //下标为0情况,相当于头删
        if (index==0){
            removeFirst();
            return;
        }

        //下标为size-1的情况,相当于尾删
        if (index==size-1){
            removeLast();
            return;
        }

        //一般情况
        //要先找到要删除节点的前一节点
        DLikedNode prev =head;
        for (int i=0 ;i<index-1;i++){
            prev=prev.next;
        }
        //此时prev指向前一个节点
        //定义两个变量,方便书写
        DLikedNode toDelete = prev.next;
        DLikedNode next = toDelete.next;

        //核心代码
        prev.next=next;
        next.prev=prev;
    }

9.指定值删除

java 复制代码
    //9.指定值删除
    public void removeByValue(int value){
        //为空情况
        if (head==null){
            return;
        }

        //一个节点的情况
        if (head.val==value){
            removeFirst();
            return;
        }

        //一般情况
        //先找到需要删除的节点
        DLikedNode cur=head;
        for (;cur!=null;cur=cur.next){
            if (cur.val==value){
                break;
            }
        }

        //如果没有找到要删除的节点,则进入
        if (cur==null){
            System.out.println("链表不存在该元素:"+value);
            return;
        }

        //如果上述没有进入,则此时要删除的值已经找到,这里定义两个变量
        DLikedNode prev= cur.prev;
        DLikedNode next =cur.next;

        //核心代码
        if (prev!=null){
            prev.next=next;
        }
        if (next!=null){
            next.prev=prev;
        }
    }

10.修改节点

java 复制代码
    //10.修改节点和获取节点元素
    public void Set(int index, int value) {
        // 空链表直接返回
        if (head == null){
            throw new IndexOutOfBoundsException("链表为空,无法修改");
        }

        //非空情况
        //先获取下标位置,则通过遍历链表,找到我们要修改的下标位置
        DLikedNode cur = head;
        int i = 0;
        while (i < index) {
            cur = cur.next;
            i++;
        }

        //如果没有找到可以修改的下标位置,则进入
        if (cur == null) {
            throw new IndexOutOfBoundsException("索引越界: " + index + ",链表长度为 " + i);
        }

        //修改节点
        cur.val = value;
    }

三:代码解析

这里我们就挑选几个来进行解析,本质都是差不多的

1.中间插入

以上这个图就是中间插入的图形画法

2.中间删除

其他的本质差不多,都是通过修改节点的指向到达我们需要的效果的

以上就是我们的全部内容了!!!!

相关推荐
paeamecium2 小时前
【PAT甲级真题】- Kuchiguse (20)
数据结构·c++·python·算法·pat考试·pat
青山木2 小时前
Hot 100 --- 全排列
java·数据结构·算法·leetcode·深度优先
起个破名想半天了4 小时前
算法与数据结构之Kruskal算法
数据结构
zhangx1234_5 小时前
java 数据结构 链表
java·数据结构·链表
不会就选b13 小时前
算法日常・每日刷题--<链表>3
数据结构·算法·链表
稚南城才子,乌衣巷风流16 小时前
块状链表:数据结构详解与实现
数据结构·链表
日拱一卒——功不唐捐18 小时前
红黑树删除(C语言)
c语言·数据结构
不如语冰19 小时前
AI大模型入门-Python进阶-上下文管理与with语句
开发语言·数据结构·数据库·人工智能·pytorch·redis·python
Angle.寻梦19 小时前
数据结构--链表
数据结构·链表