当前位置: 首页 > news >正文

【一起学数据结构与算法】Java实现双链表

目录

  • 一、双链表的概念
  • 二、双链表一些方法的实现
    • 2.1 双链表的属性
    • 2.2 打印双链表
    • 2.3 得到双链表的长度
    • 2.4 查找是否包含关键字key是否在双链表中
    • 2.5 头插法
    • 2.6 尾插法
    • 2.7 任意位置插入,第一个数据结点为0号下标
    • 2.8 删除第一次出现为key的结点
    • 2.9 删除所有key的值
    • 2.10 清空双链表
  • 三、MyLinkedList.java
  • 四、Test.java
  • 五、效果展示

一、双链表的概念

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

二、双链表一些方法的实现

2.1 双链表的属性

class ListNode {
    public int val;
    public ListNode prev;
    public ListNode next;

    public ListNode(int val) {
        this.val = val;
    }
}
public class MyLinkedList {

    public ListNode head;//指向双向链表的头节点
    public ListNode last;//指向的是尾巴结点
    }

2.2 打印双链表

打印双链表非常简单,只需要单独创一个结点cur来遍历链表并打印

//打印双向链表
public void display() {
        //和单链表的打印方式是一样的
        ListNode cur = this.head;
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

2.3 得到双链表的长度

单独创一个结点cur来遍历链表同时创一个count计数器来计算长度即可

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

2.4 查找是否包含关键字key是否在双链表中

单独创一个结点cur来遍历链表并且判断是否包含key

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

2.5 头插法

当我们想把新的结点插入到第一个结点位置处,可以先建立一个结点,然后把头结点的prev变为我们新建立结点的next值,然后将我们新建立的结点值变为null,最后将头结点指向新的插入的结点。
注意我们需要首先判断这个链表是否为空,假如为空就直接构建链表即可

//头插法
    public void addFirst(int data) {
        ListNode node = new ListNode(data);
        if (this.head == null) {
            this.head = node;
            this.last = node;
        } else {
            node.next = this.head;
            head.prev = node;
            this.head = node;
        }
    }

2.6 尾插法

尾插法顾名思义就是从结尾插入新的结点,这个和头插法过程差不多,只不过一个是改变head的位置,一个是改变last的位置。
和头插法一样,这个同样需要判断链表是否初始为空

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

2.7 任意位置插入,第一个数据结点为0号下标

首先要考虑,插入的位置是头部或尾部或中间。根据具体的位置实现具体的操作。
如果是头部,直接调用头插,如果是尾部,就直接调用尾插即可。

如果是中间插的的话:

在这里插入图片描述
1.node.next = cur.prev.next;
2.cur.prev.next = node;
3.node.prev = cur.prev;
4.cur.prev = node;
在这里插入图片描述

public ListNode searchIndex(int index) {
        ListNode cur = this.head;
        while (index != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }
    //任意位置插入,第一个数据结点为0号下标
    public void addIndex(int index, int data) {
        ListNode node = new ListNode(data);
        if (index < 0 || index >size()) {
            System.out.println("index位置不合法!");
            return;
        }
        if (index == 0) {
            addFirst(data);
            return;
        }
        if (index == size()) {
            addLast(data);
            return;
        }
        ListNode cur = searchIndex(index);
        node.next = cur.prev.next;
        cur.prev.next = node;
        node.prev = cur.prev;
        cur.prev = node;
    }

2.8 删除第一次出现为key的结点

假如是头结点的话我们还需要判断这个链表是否只有一个结点,如果是那么last指针也会为空,head指针也会为空,否则,我们只移动头指针结点就可以
当删除中间结点的时候我们可以先找到对于位置的结点cur,利用对应位置的cur.prev和cur.next确定附近两个结点,然后进行删除即可,这个删除与链表相似,只是多了一个删除头结点而已。

//删除第一次出现为key的结点
    public void remove(int key) {
        ListNode cur = this.head;

        while (cur != null) {
            if (cur.val == key) {
                if (cur == head) {
                    this.head = this.head.next;
                    if (this.head != null) {
                        this.head.prev = null;
                    } else {
                        this.last = null;
                    }
                } else {
                    cur.prev.next = cur.next;
                    if (cur.next != null) {
                        cur.next.prev = cur.prev;
                    } else {
                        this.last = this.last.prev;
                    }
                }
                return;
            }
            cur = cur.next;
        }
    }

2.9 删除所有key的值

//删除所有key的值
    public void removeAllKey(int key) {
        ListNode cur = this.head;

        while (cur != null) {
            if (cur.val == key) {
                if (cur == head) {
                    this.head = this.head.next;
                    if (this.head != null) {
                        this.head.prev = null;
                    } else {
                        this.last = null;
                    }
                } else {
                    cur.prev.next = cur.next;
                    if (cur.next != null) {
                        cur.next.prev = cur.prev;
                    } else {
                        this.last = this.last.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }

2.10 清空双链表

//清空双链表
    public void clear() {
        while (this.head != null) {
            ListNode curNext = head.next;
            this.head.next = null;
            this.head.prev = null;
            this.head = curNext;
        }
        last = null;
    }

三、MyLinkedList.java


class ListNode {
    public int val;
    public ListNode prev;
    public ListNode next;

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

public class MyLinkedList {

    public ListNode head;//指向双向链表的头节点
    public ListNode last;//指向的是尾巴结点


    //打印双向链表
    public void display() {
        //和单链表的打印方式是一样的
        ListNode cur = this.head;
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

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

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

    //头插法
    public void addFirst(int data) {
        ListNode node = new ListNode(data);
        if (this.head == null) {
            this.head = node;
            this.last = node;
        } else {
            node.next = this.head;
            head.prev = node;
            this.head = node;
        }
    }

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


    public ListNode searchIndex(int index) {
        ListNode cur = this.head;
        while (index != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }
    //任意位置插入,第一个数据结点为0号下标
    public void addIndex(int index, int data) {
        ListNode node = new ListNode(data);
        if (index < 0 || index >size()) {
            System.out.println("index位置不合法!");
            return;
        }
        if (index == 0) {
            addFirst(data);
            return;
        }
        if (index == size()) {
            addLast(data);
            return;
        }
        ListNode cur = searchIndex(index);
        node.next = cur.prev.next;
        cur.prev.next = node;
        node.prev = cur.prev;
        cur.prev = node;
    }

    //删除第一次出现为key的结点
    public void remove(int key) {
        ListNode cur = this.head;

        while (cur != null) {
            if (cur.val == key) {
                if (cur == head) {
                    this.head = this.head.next;
                    if (this.head != null) {
                        this.head.prev = null;
                    } else {
                        this.last = null;
                    }
                } else {
                    cur.prev.next = cur.next;
                    if (cur.next != null) {
                        cur.next.prev = cur.prev;
                    } else {
                        this.last = this.last.prev;
                    }
                }
                return;
            }
            cur = cur.next;
        }
    }

    //删除所有key的值
    public void removeAllKey(int key) {
        ListNode cur = this.head;

        while (cur != null) {
            if (cur.val == key) {
                if (cur == head) {
                    this.head = this.head.next;
                    if (this.head != null) {
                        this.head.prev = null;
                    } else {
                        this.last = null;
                    }
                } else {
                    cur.prev.next = cur.next;
                    if (cur.next != null) {
                        cur.next.prev = cur.prev;
                    } else {
                        this.last = this.last.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }

    //清空双链表
    public void clear() {
        while (this.head != null) {
            ListNode curNext = head.next;
            this.head.next = null;
            this.head.prev = null;
            this.head = curNext;
        }
        last = null;
    }
}

四、Test.java


public class Test {
    public static void main(String[] args) {
        MyLinkedList myLinkedList = new MyLinkedList();
        myLinkedList.addFirst(1);
        myLinkedList.addFirst(2);
        myLinkedList.addFirst(3);
        myLinkedList.addFirst(4);
        System.out.println(myLinkedList.size());
        myLinkedList.display();
        System.out.println(myLinkedList.contains(1));
        myLinkedList.addLast(1);
        myLinkedList.addLast(2);
        myLinkedList.addLast(3);
        myLinkedList.addLast(4);
        myLinkedList.display();
        myLinkedList.remove(1);
        myLinkedList.display();
        myLinkedList.removeAllKey(4);
        myLinkedList.display();
        myLinkedList.addIndex(0,99);
        myLinkedList.display();
        myLinkedList.clear();
        myLinkedList.display();

    }
}

五、效果展示

在这里插入图片描述

相关文章:

  • Spring Boot集成阿里云视频点播服务的过程记录
  • SpringBoot社区居民联系方式管理系统(附源码)
  • [ccc3.0][数字钥匙] UWB配置和使用(二)
  • MongoDB(一)
  • C#面向对象程序设计课程实验二: 实验名称:Windows 窗体程序
  • MySql主从同步
  • java基于springboot+Vue+nodejs的高校运动会报名管理系统 element
  • 单链表❀数据结构
  • Linux——孤儿进程|进程的优先级 用top命令去修改优先级 其他概念 环境变量 PATH 获取环境变量
  • Linux系统编程-网络基础(四)-协议03:数据包封装【以太网(Mac)帧:最大值1500字节称为以太网的MTU(最大传输单元),不包括帧报头长度】
  • 一次诡异的numpy数组越界访问
  • cmd炫技小方法
  • kafka搭建单机开发教程
  • 如果你需要用Python搞个二维码,那应该收藏这篇博客
  • Linux权限的认识
  • 网络传输文件的问题
  • ComponentOne 2017 V2版本正式发布
  • Create React App 使用
  • go语言学习初探(一)
  • hadoop集群管理系统搭建规划说明
  • Javascript 原型链
  • Java教程_软件开发基础
  • nginx 配置多 域名 + 多 https
  • React-生命周期杂记
  • 大快搜索数据爬虫技术实例安装教学篇
  • 温故知新之javascript面向对象
  • 小程序测试方案初探
  • 怎样选择前端框架
  • 终端用户监控:真实用户监控还是模拟监控?
  • Java数据解析之JSON
  • kubernetes资源对象--ingress
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (day 12)JavaScript学习笔记(数组3)
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (二)Eureka服务搭建,服务注册,服务发现
  • (附源码)计算机毕业设计高校学生选课系统
  • (南京观海微电子)——I3C协议介绍
  • (区间dp) (经典例题) 石子合并
  • (四)JPA - JQPL 实现增删改查
  • (转)甲方乙方——赵民谈找工作
  • (转)可以带来幸福的一本书
  • .bat文件调用java类的main方法
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .form文件_SSM框架文件上传篇
  • .net core 控制台应用程序读取配置文件app.config
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .net6+aspose.words导出word并转pdf
  • .NET分布式缓存Memcached从入门到实战
  • .NET开发人员必知的八个网站
  • .net中调用windows performance记录性能信息
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • @media screen 针对不同移动设备