Java实现单向链表

news2025/1/17 21:47:31

✅作者简介:热爱Java后端开发的一名学习者,大家可以跟我一起讨论各种问题喔。
🍎个人主页:Hhzzy99
🍊个人信条:坚持就是胜利!
💞当前专栏:Java数据结构与算法
🥭本文内容:Java实现单向链表的两种形式

单向链表


文章目录

  • 单向链表
    • 单向链表的特点
    • 单向链表代码实现(无哨兵)
    • 测试T1
    • 单向链表代码实现(有哨兵)
    • 测试T2
  • 结语


单向链表的特点

单向链表,顾名思义它是单向的,一个节点有数据部分和next指针部分组成,数据部分用来保存数据,next指针指向下一个节点,所以单向链表的每个节点都只知道下一个节点是什么,而不知道上一个节点是什么。
在这里插入图片描述

单向链表代码实现(无哨兵)

/***
 *@description:单向链表
 *@author: Hhzzy99
 *@date:2023/3/4
 **/
public class SinglyLinkedList implements Iterable<Integer>{//整体
    private Node head = null;//头指针

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            Node p = head;
            @Override
            public boolean hasNext() {//是否有下一个元素
                return p != null;
            }

            @Override
            public Integer next() {//返回当前值,并指向下一个元素
                int value = p.value;
                p = p.next;
                return value;
            }
        };
    }

    /**
     * 节点类
     */
    private static class Node{
        int value;//值
        Node next;//下一个结点指针
        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }
    /**
     * 链表头添加元素
     * @param value 元素值
     */
    public void addFirst(int value){
        //1.链表为空
//        head = new Node(value,null);
        //2.链表非空
        head = new Node(value,head);
    }

    //链表遍历
    public void loop1(Consumer<Integer> consumer){
        Node p = head;
        while(p != null){
            consumer.accept(p.value);
            p = p.next;
        }
    }

    /**
     * for循环+函数式接口Consumer
     * @param consumer 函数式接口
     */
    public void loop2(Consumer<Integer> consumer){
        for (Node p = head; p != null; p = p.next){
            consumer.accept(p.value);
        }
    }

    /**
     * 最后一个元素
     * @return Node p
     */
    private Node findLast(){
        if(head == null)
            return null;
        Node p;
        for(p = head; p.next != null; p = p.next){
        }
        return p;
    }

    /**
     * 最后面添加元素
     * @param value 元素值
     */
    public void addLast(int value){
        Node last = findLast();
        if(last == null){
            addFirst(value);
            return;
        }
        last.next = new Node(value,null);
    }

    /**
     * 寻找索引为index的元素
     * @param index 寻找的元素的索引
     * @return Node p
     */
    private Node findNode(int index){
        int i = 0;
        for(Node p = head; p.next != null; p = p.next,i++){
            if(i == index)
                return p;
        }
        return null;
    }
    /**
     * 获取索引位置的元素
     * @param index 索引值
     * @throws IllegalArgumentException - 找不到索引,抛出index非法异常
     */
    public int get(int index){
        Node p = findNode(index);
        if(p == null)
            //抛异常
            throw new IllegalArgumentException(String.format("index [%d] 不合法%n",index));
        return p.value;
    }

    /**
     * 向索引位置插入元素
     * @param index 索引值
     * @param value 待插入值
     * @throws IllegalArgumentException - 找不到索引,抛出index非法异常
     */
    public void insert(int index, int value){
        if(index == 0){
            addFirst(value);
            return;
        }
        Node prev = findNode(index - 1);//找到上一个节点
        if (prev == null)//找不到
            throw new IllegalArgumentException(String.format("index [%d] 不合法%n",index));
        prev.next = new Node(value,prev.next);
    }

    /**
     * 删除第一个元素
     * @throws IllegalArgumentException - 找不到索引,抛出index非法异常
     */
    public void removeFirst(){
        if(head == null)
            throw new IllegalArgumentException(String.format("index [%d] 不合法%n",0));
        head = head.next;
    }

    /**
     * 删除索引为index的元素
     * @param index 要删除元素的索引值
     * @throws IllegalArgumentException - 找不到索引,抛出index非法异常
     */
    public void remove(int index){
        if(index == 0){
            removeFirst();
            return;
        }
        Node prev = findNode(index - 1);//上一个节点
        if (prev == null)
            throw new IllegalArgumentException(String.format("index [%d] 不合法%n",index));
        if (prev.next == null)
            throw new IllegalArgumentException(String.format("index [%d] 不合法%n",index));
        prev.next = prev.next.next;//prev.next是被删除的元素

    }
}

测试T1

/***
 *@description:测试
 *@author: Hhzzy99
 *@date:2023/3/4
 **/
public class TestSinglyLinkedList {
    private SinglyLinkedList getSinglyLinkedList() {
        //addFirst    addLast
        SinglyLinkedList singlyLinkedList = new SinglyLinkedList();
        singlyLinkedList.addFirst(1);
        singlyLinkedList.addLast(2);
        singlyLinkedList.addLast(3);
        singlyLinkedList.addLast(4);
        return singlyLinkedList;
    }

    @Test
    //测试get()
    public void test01(){
        SinglyLinkedList singlyLinkedList = getSinglyLinkedList();
        System.out.println(singlyLinkedList.get(2));
        System.out.println(singlyLinkedList.get(5));
    }

    @Test
    //测试insert
    public void test02(){
        SinglyLinkedList singlyLinkedList = getSinglyLinkedList();
        singlyLinkedList.loop1(value -> {
            System.out.print(value + ",");
        });
        System.out.println();
        System.out.println("=============");
        singlyLinkedList.insert(0,18);
        singlyLinkedList.loop1(value -> {
            System.out.print(value + ",");
        });
    }

    @Test
    //测试remove
    public void test03(){
        SinglyLinkedList singlyLinkedList = getSinglyLinkedList();
        singlyLinkedList.loop1(value -> {
            System.out.print(value + ",");
        });
        System.out.println();
        singlyLinkedList.removeFirst();
        for (Integer ele:singlyLinkedList) {
            System.out.print(ele + ",");
        }
        System.out.println();

    }
    @Test
    //测似remove
    public void test04(){
        SinglyLinkedList singlyLinkedList = getSinglyLinkedList();
        singlyLinkedList.loop1(value -> {
            System.out.print(value + ",");
        });
        System.out.println();
        singlyLinkedList.remove(2);
        for (Integer ele:singlyLinkedList) {
            System.out.print(ele + ",");
        }
        System.out.println();
    }
}

test01:第一个获取到值,第二个超出索引,抛出预设的异常
在这里插入图片描述
test02:符合预期
在这里插入图片描述
test03:符合预期
在这里插入图片描述
test04:符合预期
在这里插入图片描述

单向链表代码实现(有哨兵)


/***
 *@description:单向链表(带哨兵)
 *@author: Hhzzy99
 *@date:2023/3/4
 **/
public class SinglyLinkedListSentinel implements Iterable<Integer>{//整体
    private Node head = new Node(999,null);//头指针->哨兵
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            Node p = head.next;
            @Override
            public boolean hasNext() {//是否有下一个元素
                return p != null;
            }

            @Override
            public Integer next() {//返回当前值,并指向下一个元素
                int value = p.value;
                p = p.next;
                return value;
            }
        };
    }

    /**
     * 节点类
     */
    private static class Node{
        int value;//值
        Node next;//下一个结点指针
        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }

    /**
     * 链表头添加元素
     * @param value 元素值
     */
    public void addFirst(int value){
        insert(0,value);
    }

    //链表遍历
    public void loop1(Consumer<Integer> consumer){
        Node p = head.next;
        while(p != null){
            consumer.accept(p.value);
            p = p.next;
        }
    }

    /**
     * for循环+函数式接口Consumer
     * @param consumer 函数式接口
     */
    public void loop2(Consumer<Integer> consumer){
        for (Node p = head.next; p != null; p = p.next){
            consumer.accept(p.value);
        }
    }

    /**
     * 最后一个元素
     * @return Node p
     */
    private Node findLast(){
        Node p;
        for(p = head; p.next != null; p = p.next){
        }
        return p;
    }

    /**
     * 最后面添加元素
     * @param value 元素值
     */
    public void addLast(int value){
        Node last = findLast();
        last.next = new Node(value,null);
    }

    /**
     * 寻找索引为index的元素
     * @param index 寻找的元素的索引
     * @return Node p
     */
    private Node findNode(int index){
        int i = -1;//从哨兵位置开始(-1)
        for(Node p = head; p.next != null; p = p.next,i++){
            if(i == index)
                return p;
        }
        return null;
    }
    /**
     * 获取索引位置的元素
     * @param index 索引值
     * @throws IllegalArgumentException - 找不到索引,抛出index非法异常
     */
    public int get(int index){
        Node p = findNode(index);
        if(p == null)
            //抛异常
            throw new IllegalArgumentException(String.format("index [%d] 不合法%n",index));
        return p.value;
    }

    /**
     * 向索引位置插入元素
     * @param index 索引值
     * @param value 待插入值
     * @throws IllegalArgumentException - 找不到索引,抛出index非法异常
     */
    public void insert(int index, int value){
        if(index == 0){
            addFirst(value);
            return;
        }
        Node prev = findNode(index - 1);//找到上一个节点
        if (prev == null)//找不到
            throw new IllegalArgumentException(String.format("index [%d] 不合法%n",index));
        prev.next = new Node(value,prev.next);
    }

    /**
     * 删除第一个元素
     * @throws IllegalArgumentException - 找不到索引,抛出index非法异常
     */
    public void removeFirst(){
        remove(0);
    }

    /**
     * 删除索引为index的元素
     * @param index 要删除元素的索引值
     * @throws IllegalArgumentException - 找不到索引,抛出index非法异常
     */
    public void remove(int index){
        Node prev = findNode(index - 1);//上一个节点
        if (prev == null)
            throw new IllegalArgumentException(String.format("index [%d] 不合法%n",index));
        if (prev.next == null)
            throw new IllegalArgumentException(String.format("index [%d] 不合法%n",index));
        prev.next = prev.next.next;//prev.next是被删除的元素

    }
}

测试T2

private SinglyLinkedListSentinel getSinglyLinkedListSentinel() {
        SinglyLinkedListSentinel list = new SinglyLinkedListSentinel();
        list.addLast(1);
        list.addLast(2);
        list.addLast(3);
        list.addLast(4);
        return list;
    }

    @Test
    public void test05(){
        SinglyLinkedListSentinel list = getSinglyLinkedListSentinel();
        list.loop2(ele->{
                System.out.print(ele+",");
            });
        System.out.println();
        System.out.println(list.get(2));
        System.out.println(list.get(10));//抛异常
    }

    @Test
    public void test06(){
        SinglyLinkedListSentinel list = getSinglyLinkedListSentinel();
        list.loop2(ele->{
            System.out.print(ele+",");
        });
        System.out.println();
        list.insert(2,7);
        list.loop2(ele->{
            System.out.print(ele+",");
        });
        System.out.println();
        list.remove(1);
        list.loop2(ele->{
            System.out.print(ele+",");
        });
//        list.insert(7,19);//抛异常
    }

test05:符合预期,抛出预设异常
在这里插入图片描述
test06:符合预期
在这里插入图片描述


结语

本文展示了Java实现单向链表的代码,希望对大家有所帮助!大家如果感兴趣可以点点赞,关注一下,你们的支持是我最强大的动力,非常感谢您的阅读(❁´◡`❁)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/387229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DevOps in China:15年来,DevOps在中国经历了什么?

纵观21世纪软件工程的发展&#xff0c;2009年一定是具有里程碑意义的一年。 自21世纪初&#xff0c;为了使软件快速适应复杂多变的市场环境、满足频繁变化的业务需求&#xff0c;软件开发开始不断应用以Scrum、精益开发、看板、极限编程为代表的敏捷开发方法&#xff0c;但此类…

STC单片机使用FatFs文件系统读取SD卡指定文件内容

STC单片机使用FatFs文件系统读取SD卡指定文件内容 🎞通过串口打印SD卡指定文件内容效果演示: 🌿所使用的单片机型号:STC15F2K60S2🌴晶振频率:11.059MHz🔗串口波特率: 9600🌼所使用的是迷你SD模块进行测试:⛳注意事项 🌿项目工程使用的内部ram比较大,需在工程…

SpringBoot项目监控-Prometheus+Grafana

目录 介绍 Prometheus Grafana 使用场景 特性 简单使用 SpringBoot配置 引入依赖 配置文件application.properties 启动 应用添加到Prometheus 下载 配置 启动 使用 Grafana Dashboard 展示应用数据 配置Prometheus数据源 配置监控面板 效果 其他 介绍 Pro…

RFID高频读写器在STM32中的应用

文章目录一、RFID简述二、产品参数及硬件连接三、模块测试四、RFID读写操作五、项目源码一、RFID简述 RFID是Radio Frequency Identification的缩写&#xff0c;是一种无接触自动识别技术&#xff0c;利用射频信号及其空间耦合传输特性&#xff0c;实现对静止的或移动中的待识别…

不懂命令, 如何将代码托管到Gitee上

1.注册码云注册地址 : https://gitee.com2. 新建仓库第一步 : 创建仓库第二步 : 给仓库起名字创建好仓库后, 我们就有了一个网络上的仓库 : 3. 将网络上的仓库克隆到本地在克隆仓库之前, 我们需要先在电脑上安装以下两个工具 >>这两个软件一定要按顺序安装, 先安装第一个…

Mybatis动态sql语句foreach中拼接正则表达式字符串注意事项

今天要说到的查询情况&#xff0c;平时项目里边其实用到的并不是很多&#xff0c;使用正则表达式无非是为了匹配结果比较灵活&#xff0c;最常见的&#xff0c;我们的查询条件一般一个参数仅仅只是一种情况的筛选&#xff0c;对于如何选择查询方式&#xff0c;主要还是要看前端…

博通仍然是美股市场最好的芯片半导体股

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 博通(AVGO)是一家快速增长的半导体公司&#xff0c;并且有很高的股息分红&#xff0c;目前其股息收益率已经高出了平均水平3.2%&#xff0c;而且估值非常合理&#xff0c;仅为预期净利润的14倍。 虽然博通也受到了经济衰退影…

One UI 5.1 更新来了

之前一直在关注One UI 5.0里提到的视频通话背景功能模块&#xff0c;结果5.0版本推送的时候没有引入&#xff0c;有先行者计划博主说是5.1里肯定会有的&#xff1b;前一两天One UI 5.1更新来了&#xff0c;然而该功能还是没有引入&#xff0c;表示很遗憾&#xff1b;本次更新新…

[媒体分流直播]媒体直播和传统直播的区别,以及媒体直播的特点

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 直播毋庸置疑已经融入到了我们生活的方方面面&#xff0c;小到才艺&#xff0c;游戏&#xff0c;大到政策的发布&#xff0c;许多企业和机构也越来越重视直播&#xff0c;那么一场活动怎…

「ABAP」OPEN SQL中FROM语句超详细解析(附案例源码解读)

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

剑指offer:在排序数组中查找数字I的个数

剑指offer&#xff1a;在排序数组中查找数字I的个数 LeetCode 2698题&#xff0c;剑指offer 53题。 击败100%的用户 题目描述 统计一个数字在排序数组中出现的次数。 示例 1: 输入: nums [5,7,7,8,8,10], target 8 输出: 2示例 2: 输入: nums [5,7,7,8,8,10], target…

模电基础(1) 半导体基础知识

基本内容&#xff1a; 1.本征半导体的基本介绍结构&#xff1b; 2.杂质半导体&#xff1b; 3.PN结的形成&#xff1b; 4.PN结的性质。 1.本征半导体 半导体&#xff1a;导电性能介于绝缘体和导体之间的物质。 本征半导体是纯净的晶体结构的半导体。 纯净→无杂质晶体结构→稳…

代码随想录中:回溯算法的基础

回溯算法是一种暴力的搜索方式&#xff1b;回溯法一般与递归同时存在。 回溯法&#xff0c;一般可以解决如下几种问题&#xff1a; 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合切割问题&#xff1a;一个字符串按一定规则有几种切割方式子集问题&#xff1a;一个…

SpringBoot 集成 RabbitMQ

SpringBoot 集成 RabbitMQ 1.应用实例 需求说明/图解 -P : 消息的发送者/生产者 -C : 消息的接受者/消费者 -中间表示队列 完成步骤 添加依赖 <!--rabbitmq-需要的 AMQP 依赖--> <dependency><groupId>org.springframework.boot</groupId><art…

python判断控制语句和输出练习

作业2&#xff1a;判断一个数&#xff0c;是否是2的指数 2的指数 0000 0010 0000 0001 0000 0100 0000 0011 0000 1000 0000 0111 0001 0000 0000 1111 提示&#xff1a;所有2的指数&#xff1a;n&(n - 1) 0 作业3&#xff…

【spring】spring5特性

1、整个 Spring5 框架的代码基于 Java8&#xff0c;运行时兼容 JDK9&#xff0c;许多不建议使用的类和方 法在代码库中删除 日志框架 2、Spring 5.0 框架自带了通用的日志封装 &#xff08;1&#xff09;Spring5 已经移除 Log4jConfigListener&#xff0c;官方建议使用 Log4j…

Linux23 --- 三次握手四次挥手、客户端编程流程代码、命令netstat、 tcp协议是个面向链接的可靠的流式服务

tcp协议特点&#xff1a; 面向连接的&#xff0c;可靠的&#xff0c;流式服务。 一、三次握手 、四次挥手 链接的建立通过三次握手&#xff0c;链接的断开通过四次挥手 1、TCP固定头部结构 2、三次握手 3、四次挥手 二、命令 - netstat -natp n - 用数字来表示ip地址、端口…

【8】【用户操作日志】操作日志SpringBootStarter

操作日志 此版本操作日志主要就是通过AOP拦截器实现的&#xff0c;整体主要分为AOP拦截器、自定义函数、日志上下文、扩展接口&#xff1b;组件提供了6个扩展点&#xff0c;自定义函数、日志上下文、用户信息获取&#xff0c;日志保存&#xff0c;自定义异常获取&#xff0c;入…

2023王道考研数据结构笔记第四章串

第四章 串 4.1 串的定义 4.1.1 串的相关概念 串&#xff1a;即字符串&#xff08;String&#xff09;是由零个或多个字符组成的有限序列。一般记为S‘a1a2…an’ (n>0) 其中S是串名&#xff0c;单引号&#xff08;注&#xff1a;有的地方用双引号&#xff0c;如Java、C&am…

4. Unity之文件资源和其它杂项

1. 资源文件 unity中的Assets文件夹下的文件都可以称为时资源文件&#xff0c;包括模型文件、材质文件、纹理贴图文件、脚本文件、音频文件等&#xff0c;如果想查看某一个文件在电脑中的保存路径&#xff0c;可以选中指定文件后&#xff0c;单击鼠标右键选择show in Explorer…