Java实现单链表

news2024/11/24 22:39:52

目录

一.单链表

二.单链表基本操作的实现

1.单链表类、属性的定义

2.求链表长度

3.链表是否包含值为key的节点

4.添加元素

5.删除节点

6.清空链表

三、完整代码


一.单链表

链表是一种在物理存储结构非连续的存储结构,数据元素的逻辑顺序通过链表中的引用链接次序实现。链表的结构多样,我们通过实现无头单向非循环链表,来进一步理解链表。

从图中可以看出,链表在逻辑上连续的,但在物理存储结构上不一定是连续的

由于链表是单向的,可以通过前一个节点访问后一个节点,不能通过后一个节点访问前一个结点

二.单链表基本操作的实现

1.单链表类、属性的定义

要创建链表首先要有节点,我们可以将节点定义为内部类

public class MySingleList{
    static class ListNode{
        //存放当前结点的值
        private int val;
        //存放下一节点的地址
        private ListNode next;
        public ListNode(){}
        public ListNode(int val){
            this.val = val;
        }
    }
}

由于链表是通过前一个节点访问下一个节点的,因此我们需要知道链表的第一个节点,因此我们需要定义一个头节点

private ListNode head;//第一个节点

2.求链表长度

 定义变量count用以计算,遍历链表,统计链表节点个数

//求链表长度
public int size() {
    int count = 0;
    //定义节点cur,用于遍历链表
    ListNode cur = head;
    while(cur != null){
        count++;
        //指向下一节点
        cur = cur.next;
    }
    return count;
}

3.链表是否包含值为key的节点

遍历链表,判断节点的值是否等于key

public boolean contains(int key) {
    ListNode cur = head;
    while(cur != null){
        if(cur.val == key){
            return true;
        }
        cur = cur.next;
    }
    return false;
}

4.添加元素

链表添加元素的方式通常有三种,头插、尾插和在指定位置添加元素。

头插:在链表的第一个节点前插入元素

 实现头插,就是让要插入的节点node指向原本链表的头节点head,再更新链表的第一个节点,让head指向新插入的节点

//头插
public void addFirst(int data) {
    //创建新节点
    ListNode listNode = new ListNode(data);
    listNode.next = head;
    head = listNode;
}

尾插:在链表的最后插入元素

实现尾插,首先要找到链表的最后一个节点,再将最后一个节点的next更新为新节点即可

//尾插
public void addLast(int data) {
    ListNode newNode = new ListNode(data);
    //若链表为空,直接将head更新为插入节点
    if(head == null){
        head = newNode;
    }else{
        //通过遍历找到最后一个节点
        ListNode cur = head;
        while(cur.next != null){
            cur = cur.next;
        }
        cur.next = newNode;
    }
}

在指定位置添加元素

 在指定位置添加元素,首先要判断指定位置index是否合法,若index < 0 或 index > size,则不能添加元素,然后通过遍历找到节点插入的位置,由于链表为单链表,不能通过后一节点找到前一节点,因此,我们需要找到插入位置的前驱节点,然后通过前驱节点实现链表在index位置的插入

//在任意位置添加元素
public void addIndex(int index, int data) {
    //index不正确,无法添加元素
    if(index < 0 || index > size()){
        throw new RuntimeException("输入位置不正确,无法添加元素!");
    }else if(index == 0){//在0位置插入,即为头插
        addFirst(data);
    }else{
        ListNode cur = head;//用cur遍历链表,找到前驱节点
        ListNode listNode = new ListNode(data);
        int count = 0;
        while(count != index-1){
            count++;
            cur = cur.next;
        }
        //添加元素
        listNode.next = cur.next;
        cur.next = listNode;
    }
}

5.删除节点

删除第一个值为key的节点:与在指定位置添加元素相同,我们需要找到第一个值为key的节点node的前驱节点,然后才能删除值为key的节点。由于JVM会将未被任何引用指向的对象回收掉,我们只需让node的前驱节点指向node的下一节点,即可实现删除

//删除第一个值为key的节点
public boolean remove(int key) {
    ListNode cur = head;
    //链表第一个节点的值即为key,头删
    if(head.val == key){
        head = head.next;
        return true;
    }//通过遍历找到第一个值为key的节点的前驱节点
    while(cur.next != null){
        if(cur.next.val == key){//找到了,删除节点
            cur.next = cur.next.next;
            return true;
        }
        cur = cur.next;
    }
    return false;//未找到值未key的节点,返回false
}

删除所有值为key的节点:首先要找到值为key的节点node,将node的上一节点指向node的下一节点,即可删除值为key的节点,注意考虑头节点值为key的情况,要删除链表中所有值为key的节点,利用while循环即可实现。

//删除所有值为key的节点
public void removeAllKey(int key) {
    //若链表为空,则直接返回null
    if(head == null){
        return;
    }
    ListNode cur = head;
    while(cur.next != null){
        if(cur.next.val == key){
            cur.next = cur.next.next;
        }else{
            cur = cur.next;
        }
    }
    //单独考虑头节点的值是否等于val
    if(head.val == key){
        head = head.next;
    }
}

6.清空链表

由于JVM会将未被任何引用指向的对象回收掉,清空链表可以将每个节点的指向都置为null,即切断节点之间的链接,也可以直接将head置为null

将每个节点的指向都置为null

//清空链表
public void clear() {
    if(head == null){//链表本身为空
        return;
    }
    ListNode cur = head;
    while(cur != null){
        ListNode next = cur.next;//记录下一节点
        cur.next = null;
        cur = next;
    }
}

直接将head置为null

//清空链表
public void clear() {
    head = null;
}

三、完整代码

public class MySingleList {
    static class ListNode{
        //存放当前结点的值
        private int val;
        //存放下一节点的地址
        private ListNode next;
        public ListNode(){}
        public ListNode(int val){
            this.val = val;
        }
    }
    private ListNode head;//第一个节点
    //求链表长度
    public int size() {
        int count = 0;
        //定义节点cur,用于遍历链表
        ListNode cur = head;
        while(cur != null){
            count++;
            //指向下一节点
            cur = cur.next;
        }
        return count;
    }
    //链表是否包含值为key的节点
    public boolean contains(int key) {
        ListNode cur = head;
        while(cur != null){
            if(cur.val == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    //头插
    public void addFirst(int data) {
        //创建新节点
        ListNode listNode = new ListNode(data);
        listNode.next = head;
        head = listNode;
    }
    //尾插
    public void addLast(int data) {
        ListNode newNode = new ListNode(data);
        //若链表为空,直接将head更新为插入节点
        if(head == null){
            head = newNode;
        }else{
            //通过遍历找到最后一个节点
            ListNode cur = head;
            while(cur.next != null){
                cur = cur.next;
            }
            cur.next = newNode;
        }
    }
    //在任意位置添加元素
    public void addIndex(int index, int data) {
        //index不正确,无法添加元素
        if(index < 0 || index > size()){
            throw new RuntimeException("输入位置不正确,无法添加元素!");
        }else if(index == 0){//在0位置插入,即为头插
            addFirst(data);
        }else{
            ListNode cur = head;//用cur遍历链表,找到前驱节点
            ListNode listNode = new ListNode(data);
            int count = 0;
            while(count != index-1){
                count++;
                cur = cur.next;
            }
            //添加元素
            listNode.next = cur.next;
            cur.next = listNode;
        }
    }
    //删除第一个值为key的节点
    public boolean remove(int key) {
        ListNode cur = head;
        //链表第一个节点的值即为key,头删
        if(head.val == key){
            head = head.next;
            return true;
        }//通过遍历找到第一个值为key的节点的前驱节点
        while(cur.next != null){
            if(cur.next.val == key){//找到了,删除节点
                cur.next = cur.next.next;
                return true;
            }
            cur = cur.next;
        }
        return false;//未找到值未key的节点,返回false
    }
    //删除所有值为key的节点
    public void removeAllKey(int key) {
        //若链表为空,则直接返回null
        if(head == null){
            return;
        }
        ListNode cur = head;
        while(cur.next != null){
            if(cur.next.val == key){
                cur.next = cur.next.next;
            }else{
                cur = cur.next;
            }
        }
        //单独考虑头节点的值是否等于val
        if(head.val == key){
            head = head.next;
        }
    }
    //清空链表
    public void clear() {
        if(head == null){//链表本身为空
            return;
        }
        ListNode cur = head;
        while(cur != null){
            ListNode next = cur.next;//记录下一节点
            cur.next = null;
            cur = next;
        }
        //或直接将head置为null
        //head = null;
    }
}

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

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

相关文章

【深度学习】卷积神经网络(LeNet)【文章重新修改中】

卷积神经网络 LeNet 前言LeNet 模型代码实现MINST代码分块解析1 构建 LeNet 网络结构2 加载数据集3 初始化模型和优化器4 训练模型5 训练完成 完整代码 Fashion-MINST代码分块解析1 构建 LeNet 网络结构2 初始化模型参数3 加载数据集4 定义损失函数和优化器5 训练模型 完整代码…

AIDAO,将会引领我们走向何方?

人工智能&#xff08;AI&#xff09;和分布式自治组织&#xff08;DAO&#xff09;都是区块链赛道的热门项目之一&#xff0c;他们看似在不同的领域独立发展&#xff0c;然而&#xff0c;它们之间也存在着巨大的协同潜力。 未来&#xff0c;AI有望成为推动DAO发展的重要动力&a…

【Java 基础篇】Java并发包详解

多线程编程是Java开发中一个重要的方面&#xff0c;它能够提高程序的性能和响应能力。然而&#xff0c;多线程编程也伴随着一系列的挑战&#xff0c;如线程安全、死锁、性能问题等。为了解决这些问题&#xff0c;Java提供了一套强大的并发包。本文将详细介绍Java并发包的各个组…

Docker网络问题:容器无法访问外部网络

Docker网络问题&#xff1a;容器无法访问外部网络 &#x1f61f; Docker网络问题&#xff1a;容器无法访问外部网络 &#x1f61f;摘要 &#x1f914;引言 &#x1f310;正文 &#x1f913;为什么容器无法访问外部网络&#xff1f; &#x1f615;1. 网络配置错误2. 防火墙设置3…

WebGL 选中物体

目录 前言 如何实现选中物体 示例程序&#xff08;PickObject.js&#xff09; 代码详解 gl.readPixels&#xff08;&#xff09;函数规范 示例效果 前言 有些三维应用程序需要允许用户能够交互地操纵三维物体&#xff0c;要这样做首先就得允许用户选中某个物体。对物体…

三维建模软件Cinema 4D 2024 mac(c4d2024)中文版特点

Cinema 4D 2024 mac是一款专业的三维建模、动画和渲染软件&#xff0c;c4d2024 可以用于电影制作、广告设计、工业设计等领域。 Cinema 4D 2024具有强大的建模工具&#xff0c;可以创建各种复杂的几何体&#xff0c;包括多边形网格、NURBS曲线和体积对象。它还提供了丰富的材质…

Docker快速入门到项目部署,MySQL部署+Nginx部署

《Docker》是微服务在企业落地的最后一块拼图。微服务项目由于拆分粒度细&#xff0c;服务部署环境复杂&#xff0c;部署实例很多&#xff0c;维护困难。而Docker则可以解决项目部署的各种环境问题&#xff0c;让开发、运维一体化&#xff0c;真正实现持续集成、持续部署。大大…

一文详解自动化测试框架知识

前言 自动化测试因其节约成本、提高效率、减少手动干预等优势已经日渐成为测试人员的“潮流”&#xff0c;从业人员日益清楚地明白实现自动化框架是软件自动化项目成功的关键因素之一。 我们将从什么是真正的自动化测试框架、自动化脚本如何工作以及自动化测试框架会如何在测…

three.js——辅助器AxesHelper和轨道控制器OrbitControls的使用

辅助器AxesHelper和轨道控制器OrbitControls的使用 前言效果图1、辅助器AxesHelper:是物体出现辅助的x/y/z轴2、轨道控制器OrbitControls2.1导入OrbitControls文件2.2 使用2.3 如果OrbitControls改变了相机参数&#xff0c;重新调用渲染器渲染三维场景 前言 1、AxesHelper 官网…

搭建GraphQL服务

js版 GraphQL在 NodeJS 服务端中使用最多 安装graphql-yoga: npm install graphql-yoga 新建index.js: const {GraphQLServer} require("graphql-yoga")const server new GraphQLServer({ typeDefs: type Query { hello(name:String):String! …

由于找不到vcruntime140_1.dll怎么修复,详细修复步骤分享

在使用电脑过程中&#xff0c;可能会遇到一些错误提示&#xff0c;其中之一是找不到vcruntime140_1.dll的问题。这使得许多用户感到困扰&#xff0c;不知道该如何解决这个问题。小编将详细介绍vcruntime140_1.dll的作用以及解决找不到该文件的方法&#xff0c;帮助你摆脱困境。…

前端进阶--深入理解JavaScript

1、JS的作用域和作用域链 作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问&#xff0c;通过作用域链&#xff0c;我们可以访问到外层环境的变量和函数。作用域链的本质上是一个指向变量对象的指针列表。变量对象是一个包含了执行环境中所有变量和函数的对象…

openpnp - use STM32 arduino on SchultzController

文章目录 openpnp - use STM32 arduino on SchultzController概述笔记官方的起始文档增加arduino第三方开发板库索引地址改好后, 能编译过的工程SchultzController.inoFeeder.hFeeder.cpp再验证一下内存是否够用补充 - 如果是自己做的板子END openpnp - use STM32 arduino on S…

开发者福利!李彦宏将在百度世界大会手把手教你做AI原生应用

目录 一、写在前面 二、大模型社区 2.1 加入频道 2.2 创建应用 一、写在前面 1. “把最先进的技术用到极致&#xff0c;把最先进的应用做到极致。” 2. “每个产品都在热火朝天地重构&#xff0c;不断加深对AI原生应用的理解。” 3. “这就是真正的AI原生应用&#xff0c;这…

深度学习修炼(三)卷积操作 | 边界填充、跨步、多输入输出通道、汇聚池化

文章目录 1. 卷积基本操作2 现代卷积进阶武器操作2.1 边界 填充2.2 跨步 步幅2.3 多输入输出通道2.4 汇聚 池化 3. 卷积层设计 之前我们讲了 线性分类器 深度学习修炼&#xff08;一&#xff09;线性分类器 | 权值理解、支撑向量机损失、梯度下降算法通俗理解_Qodi的博客-CSDN博…

看完这篇 教你玩转渗透测试靶机Vulnhub——Toppo: 1

Vulnhub靶机Toppo: 1渗透测试详解 Vulnhub靶机介绍&#xff1a;Vulnhub靶机下载&#xff1a;Vulnhub靶机安装&#xff1a;①&#xff1a;信息收集&#xff1a;②&#xff1a;SSH登入&#xff1a;③&#xff1a;SUID提权&#xff08;python2.7&#xff09;&#xff1a;④&#x…

JAVA面经整理(2)

一)解决哈希冲突的方法有哪些&#xff1f; 哈希冲突指的是在哈希表中&#xff0c;不同的键值映射到了相同的哈希桶&#xff0c;也就是数组索引&#xff0c;导致键值对的冲突 1)设立合适的哈希函数:通过哈希函数计算出来的地址要均匀的分布在整个空间中 2)负载因子调节: 2.1)开放…

Python yaml 详解

文章目录 1 概述1.1 特点1.2 导入 2 对象2.1 字典2.2 数组2.3 复合结构 3 操作3.1 读取3.2 写入 1 概述 1.1 特点 yaml 文件是一种数据序列化语言&#xff0c;广泛用于配置文件、日志文件等特点&#xff1a; ① 大小写敏感。② 使用缩进表示层级关系。缩进时不允许使用 Tab 键…

【VastbaseG100】 FATAL: The account has been locked.

使用VastbaseG100 数据库&#xff0c;查询数据报错。 org.postgresql.util.PSQLException: FATAL: The account has been locked. 帐户已被锁定。 解锁账户呗 ALTER ROLE doc ACCOUNT UNLOCK;ALTER ROLE 用户名 ACCOUNT UNLOCK; 修改密码 ALTER ROLE doc IDENTIFIED BY ZhangS…

【实战项目之个人博客】

目录 项目背景 项目技术栈 项目介绍 项目亮点 项目启动 1.创建SSM&#xff08;省略&#xff09; 2.配置项目信息 3.将前端页面加入到项目中 4.初始化数据库 5.创建标准分层的目录 6.创建和编写项目中的公共代码以及常用配置 7.创建和编写业务的Entity、Mapper、…