【数据结构】实现单链表的增删查

news2025/1/10 10:24:24

目录

  • 1.定义接口
  • 2.无头单链表实现接口
    • 2.1 头插addFirst
    • 2.2 尾插add
    • 2.3 删除元素remove
    • 2.4 修改元素set
    • 2.5 获取元素get
  • 3.带头单链表实现接口
    • 3.1 头插addFirst
    • 3.2 尾插add
    • 3.3 删除元素remove
    • 3.4 判断是否包含元素element

1.定义接口

public interface SeqList<E>{
    //默认尾插
    void add(E element);
    // 在线性表中插入新元素,插入后的元素下标为index
    void add(int index,E element);
    //头插
    public void addFirst(E val);
    // 删除当前线性表中索引为index的元素,返回删除的元素值
    E removeByIndex(int index);
    // 删除当前线性表中第一个值为element的元素
    void removeByValue(E element);
    // 删除当前线性表中所有值为element的元素
    void removeAllValue(E element);
    // 将当前线性表中index位置的元素替换为element,返回替换前的元素值
    E set(int index,E element);
    //返回索引位index的元素
    E get(int index);
    //查询是否包含element元素
    boolean contains(E element);
}

2.无头单链表实现接口

链表类和节点类的定义:

public class SingleLinkedList<E> implements SeqList<E>{
    private Node head ;//第一节车厢的地址
    private int size;//车厢节点的个数,保存的元素个数

    //定义一个车厢类,车厢作为火车的私有内部类,对外部完全隐藏
    private class Node{
        E val;//保存的元素
        Node next;//下一节车厢的地址
        //构造方法
        Node(E val){
            this.val=val;
        }
    }
 }

2.1 头插addFirst

public void addFirst(E val){
	Node node=new Node(val);
	node.next=head;
	node=head;
	size++;
}

图解:

在这里插入图片描述

2.2 尾插add

从中间位置插入:

	@Override
    public void add(int index, E element) {
        if(index<0||index>size){
            throw new IllegalArgumentException("add index ILLegal");
        }
        //判断没有前驱的情况
        if(index==0){
            addFirst(element);
            return;
        }
        //中间位置插入
        Node prey=head;
        for(int i=0;i<index-1;i++){
            prey=prey.next;
        }
        Node node=new Node(element);
        node.next=prey.next;
        prey.next=node;
        size++;
    }

图解:假定index=2
在这里插入图片描述

尾插:

    @Override
    public void add(E element) {
        add(size,element);
    }

2.3 删除元素remove

删除当前线性表中索引为index的元素,返回删除的元素值:

    @Override
    public E removeByIndex(int index) {
        if(rangeCheck(index)){
            throw new IllegalArgumentException("remove index Illegal");
        }
        //头节点的删除
        if(index==0){
            Node node=head;
            head=head.next;
            node.next=null;
            size--;
            return node.val;
        }
        //中间位置删除
        Node prey=head;
        for(int i=0;i<index-1;i++){
            prey=prey.next;
        }
        Node node=prey.next;
        prey.next=node.next;
        node.next=null;
        size--;
        return node.val;
    }

图解:

在这里插入图片描述

删除当前线性表中第一个值为element的元素:

    @Override
    public void removeByValue(E element) {
        //1.base case
        if(head==null){
            return;
        }
        //2.判断头节点恰好是待删除的节点
        if(head.val.equals(element)){
            head=head.next;
            size--;
            return;
        }
        //3.此时头节点不为空其一定不是待删除的节点
        Node prey=head;
        while(prey.next!=null){
            if(prey.next.equals(element)){
                prey.next=prey.next.next;
                size--;
                return;
            }
            prey=prey.next;
        }
        //4.当前链表不存在值为element的元素
        System.out.println("当前链表不存在值为"+element+"的元素");
    }

删除当前线性表中所有值为element的元素:

    @Override
    public void removeAllValue(E element) {
        //1.base case
        if(head==null){
            return;
        }
        //2.若头节点就是待删除的节点且出现连续的待删除的节点
        while(head!=null && head.val.equals(element)){
            head=head.next;
            size--;
        }
        //整个链表已经删完了
        if(head==null){
            return;
        }
        //3.头节点一定不是待删除的元素且链表不为空
        Node prey=head;
        while(prey.next!=null){
            if(prey.next.val.equals(element)){
                prey.next=prey.next.next;
                size--;
            }else{
                //只有后继节点不是待删除的节点才能移动Prey的引用
                prey=prey.next;
            }
        }
    }

2.4 修改元素set

将当前线性表中index位置的元素替换为element,返回替换前的元素值:

    // 将当前线性表中index位置的元素替换为element,返回替换前的元素值
    @Override
    public E set(int index, E element) {
        if(!rangeCheck(index)){
            throw new IllegalArgumentException("set index illegal");
        }
        Node x=head;
        //遍历,走到index对应的元素
        for (int i = 0; i < index; i++) {
            x=x.next;
        }
        E oldVal=x.val;
        x.val=element;
        return oldVal;
    }
    //合法性校验
    private boolean rangeCheck(int index){
        if(index<0||index>=size){
            return false;
        }
        return true;
    }

2.5 获取元素get

返回索引为index的元素:

    @Override
    public E get(int index) {
        if(!rangeCheck(index)){
            throw new IllegalArgumentException("get index illegal");
        }
        Node x=head;
        for(int i=0;i<index;i++){
            x=x.next;
        }
        return x.val;
    }

3.带头单链表实现接口

在这里插入图片描述

由于单链表中都需要额外处理头结点的情况,引入一个虚拟头结点,这个节点不存在具体的值,就作为链表的头来使用,使每个有值的节点都有一个前驱。(所有操作都统一了,无论是插入还是删除,都可以看作是中间位置的插入和删除)

链表类和节点类的定义:

public class SingleLinkedListWithHead <E> implements SeqList<E>{
    //当前链表一定存在火车头且不存储任何元素
    private Node dummyHead=new Node(null);
    //具体的元素个数
    private int size;
    private class Node{
        E val;
        Node next;
        Node(E val){
            this.val=val;
        }
    }
}

3.1 头插addFirst

    public void addFirst(E val){
        Node node=new Node(val);
        node.next=dummyHead.next;
        dummyHead.next=node;
        size++;
    }

图解:

在这里插入图片描述

3.2 尾插add

    @Override
    public void add(E element) {
        add(size,element);
        return;
    }

    @Override
    public void add(int index, E element) {
        if(index<0||index>size){
            throw new IllegalArgumentException("Remove index illegal");
        }
        Node prey=dummyHead;
        for(int i=0;i<index;i++){
            prey=prey.next;
        }
        Node node=new Node(element);
        node.next=prey.next;
        prey.next=node;
        size++;
    }

3.3 删除元素remove

    @Override
    public void removeAllValue(E element) {
        //prey一定指向不是待删除的节点
        Node prev=dummyHead;
        while(prev.next!=null){
            if(prev.next.val==element){
                prev.next=prev.next.next;
                size--;
            }else{
                prev=prev.next;
            }
        }
    }

3.4 判断是否包含元素element

    @Override
    public boolean contains(E element) {
        while(dummyHead.next!=null){
            if(dummyHead.next.val.equals(element)){
                return true;
            }
            dummyHead.next=dummyHead.next.next;
        }
        return false;
    }

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

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

相关文章

中兴服务器支持百度“文心一言”,助力AI产业发展

前段时间&#xff0c;中兴和百度正式对外宣布中兴服务器将会支持百度“文心一言”&#xff0c;为其提供更加强劲的算力支撑&#xff0c;从而加速“文心一言”的完事升级与更新迭代&#xff0c;助力AI产业化应用和生态的繁荣发展。   “文心一言”是百度基于文心大模型技术推出…

dubbo配置---重试与版本号

1、重试次数 失败自动切换&#xff0c;当出现失败&#xff0c;重试其它服务器&#xff0c;但重试会带来更长延迟。可通过 retries“2”{默认} 来设置重试次数(不含第一次)。 &#xff08;1&#xff09;在调用端&#xff0c;Reference注解添加属性 retries&#xff0c;设置重试…

P3372 【模板】线段树 1 常规做法

题目 思路 普普通通的线段树做法 代码 #include<bits/stdc.h> using namespace std; const int M1e55; #define lc(x) ((x)<<1) #define rc(x) ((x)<<1|1) #define int long long int n,m; int a[M],sm[M<<2],tag[M<<2]; void pushup(int x) …

Linux系统管理:虚拟机Alpine Linux安装

目录 一、理论 1.Alpine Linux 二、实验 1.Alpine Linux安装 三、问题 1.Alpine Linux 缺少VIM命令 2.Alpine Linux SSH连接不上 3.Alpine Linux IP配置 四、总结 一、理论 1.Alpine Linux &#xff08;1&#xff09;概念 Alpine 操作系统是一个面向安全的轻型 Lin…

Linux 第五章之软件包管理器 yum

一、什么是软件包 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序.但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上, 通过包管理器可以很方便的获取到这个编译好的…

概率论与数理统计复习总结3

概率论与数理统计复习总结&#xff0c;仅供笔者复习使用&#xff0c;参考教材&#xff1a; 《概率论与数理统计》/ 荣腾中主编. — 第 2 版. 高等教育出版社《2024高途考研数学——概率基础精讲》王喆 概率论与数理统计实际上是两个互补的分支&#xff1a;概率论 在 已知随机…

【微服务】springboot整合redis哨兵集群使用详解

目录 一、前言 二、环境准备 三、安装redis 3.1 前置准备 3.1.1 下载安装包 3.1.2 准备依赖环境 3.1.3 上传并解压包 3.2 执行安装 四、搭建redis主从集群 4.1 环境准备 4.2 搭建过程 4.2.1 创建实例文件目录 4.2.2 修改redis.conf配置文件 4.2.3 拷贝配置文件 4…

设计模式之开闭原则

什么是开闭原则? 开放封闭原则称为OCP原则&#xff08;Open Closed Principle&#xff09;是所有面向对象原则的核心。 “开闭原则”是面向对象编程中最基础和最重要的设计原则之一。 软件设计本身所追求的目标就是封装变化、降低耦合&#xff0c;而开放封闭原则正是对这一…

GICI-LIB代码框架学习

一直想要学习多源融合&#xff0c;一直各种琐碎事情耽搁&#xff0c;没有进展。终于&#xff0c;今天以上海交大开源的GNSS/INS/Camera组合导航库为开始。 二话不说&#xff0c;github下载代码后&#xff0c;不编译&#xff0c;不运行&#xff0c;直接vs code打开工程&#xf…

【excel常用文本函数大全上】

目录索引 LEFT&#xff1a;公式&#xff1a;举例&#xff1a; RIGHT&#xff1a;公式&#xff1a;举例&#xff1a; MID&#xff1a;公式&#xff1a;举例&#xff1a; FIND&#xff1a;公式&#xff1a;举例&#xff1a; LEN&#xff1a;公式&#xff1a;举例&#xff1a; LEN…

base64编码转图片

String data"data:image/jpeg;base64,/9j/4T...."; // String data"null";String taskid"4028488c894831fd01894cbf0c6f0033";if(data.equals("")||data.equals("null")){System.out.println("无朝向照片可…

Java IO编程(一)

目录 1.File类 2.字节输入输出流(InputStream Outputstream) 3.Writer与Reader字符输入输出流 4.打印流 1.File类 file类专门用于管理file文件的&#xff0c;比如文件的创建&#xff0c;删除&#xff0c;修改名称等等 以下是File类的常用方法&#xff1a; 方法描述exists()…

《Opencv入门到项目实战》(一):Opencv安装及图像基本操作

文章目录 0.Opencv介绍及环境配置1.图像读取1.1 彩色图像读取1.2 灰色图像读取 2.视频读取3.ROI读取3.1 图形切片处理3.2 提取颜色通道 4.图像填充5.数值运算与图像融合5.1 加法运算5.2 图像融合 6. 总结 0.Opencv介绍及环境配置 OpenCV是一个强大的计算机视觉库&#xff0c;它…

CS5265 USB-C to HDMI 4k@60Hz单转方案

CS5265AN是一款高性能Type-C/DP1.4至HDMI2.0b转换器芯片&#xff0c;集成了DP1.4兼容接收机和HDMI2.0b兼容发射机&#xff0c;还配备了CC控制器用于CC通信&#xff0c;实现DP Alt模式。DP接口包括4条主通道、辅助通道和HPD信号&#xff0c;接收器支持每通道最大5.4Gbps数据速率…

通过 CCIP 构建跨链应用(5 个案例)

Chainlink 的跨链互操作性协议&#xff08;CCIP&#xff09;是一种新的通用跨链通信协议&#xff0c;为智能合约开发人员提供了以最小化信任的方式在区块链网络之间传输数据和通证的能力。 目前&#xff0c;部署在多个区块链上的应用程序面临着资产、流动性和用户的碎片化问题…

【dfs分解质因数】CF27E

Problem - 27E - Codeforces 题意&#xff1a; 思路&#xff1a; 爆搜分解质因子的模板题&#xff0c;记录一下板子 Code&#xff1a; #include <bits/stdc.h>#define int long longusing namespace std;const int mxn1e610; const int mxe1e610; const int mxv1e610…

跨部门协作,企业图文档管理的协同管理的重要性

随着企业规模的扩大和业务流程的复杂化&#xff0c;图文档管理涉及的部门和人员越来越多&#xff0c;因此跨部门协作成为了必不可少的管理方式。在线图文档管理作为现代企业的数字化解决方案之一&#xff0c;为跨部门协作提供了强大的支持和便利。在线图文档管理在企业图文档管…

什么是图像特征?如何让计算机理解图像特征?

图像的特征 大多数人都玩过拼图游戏。首先拿到完整图像的碎片&#xff0c;然后把这些碎片以正确的方式排列起来从而重建这幅图像。如果把拼图游戏的原理写成计算机程序&#xff0c;那计算机就也会玩拼图游戏了。 在拼图时&#xff0c;我们要寻找一些唯一的特征&#xff0c;这…

React Dva项目 Model中编写与调用异步函数

上文 React Dva项目中模仿网络请求数据方法 中&#xff0c;我们用项目方法模拟了后端请求的数据 那么 今天我们就在models中尝试去使用一下这种异步获取数据的方法 之前 我们在文章 React Dva项目创建Model,并演示数据管理与函数调用 中已经接触过Model了 也可以理解为 它就是 …

火爆全网,Fiddler手机抓包-接口测试辅助实战(最全总结)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Fiddler是一款安装…