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

目录

  • 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;
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第九节 文件操作

文章目录 1. 引言2. 基本的文件操作2.1 打开文件2.1.1 mode 访问模式2.1.2 文件不存在,则创建文件2.1.3 二进制打开文件2.1.4 打开文件时&#xff0c;指定编码方式 2.2 关闭文件2.2.1 with 打开语句结构 2.3 文件的读写2.3.1 写入文件内容2.3.2 读取文件2.3.2.1 read&#xff0…

TCP的三次握手四次挥手

TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。 三次握手&#xff1a;为了对每次发送的数据量进行跟踪与协商&#xff0c;确保数据段的发送和接收同步&#xff0c;根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系&#xff0c;并建立虚连接。 四次挥手&a…

JVM系统优化实践(24):ZGC(一)

您好&#xff0c;这里是「码农镖局」CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 截止到目前&#xff0c;算上ZGC&#xff0c;Java一共有九种类型的GC&#xff0c;它们分别是&#xff1a; 1、Serial GC 串行/作用于新生代/复制算法/响应速度优先/适用于单…

pointpillars在Ubuntu2004训练的总结

1、找到pointpcdet-master之后在此打开终端输入code进入VScode界面 code 2、激活pp环境 conda activate pp 3、cd进入tools cd tools 4、将kitti数据集准备好放入data路径下之后开始训练 python train.py --cfg_file cfgs/kitti_models/pointpillar.yaml 5、训练完成之…

GraphGT: Machine Learning Datasets for Graph Generation and Transformation

一、文章来源 > Du Y, Wang S, Guo X, et al. Graphgt: Machine learning datasets for graph generation and transformation[C]//Thirty-fifth Conference on Neural Information Processing Systems Datasets and Benchmarks Track (Round 2). 2021.二、概述 1、文章提出…

CMU-CERT内部威胁数据集 r4.2版本介绍

CMU-CERT内部威胁数据集 r4.2版本介绍 一、相关介绍二、CMU-CERT r4.2版本内容三、重大变更 一、相关介绍 “CMU”是卡内基梅隆大学&#xff08;Carnegie Mellon University&#xff09;的简称。 “CERT”是卡内基梅隆大学的一个研究中心叫“CERT”&#xff0c;主要研究内部威…

汇川伺服常见故障处理

伺服系统故障拓扑图 Er.941 变更参数需重新上电生效 产生机理:伺服驱动器的功能码属性“生效时间”为“再次通电”时,该功能码参数值变更后,驱动器提醒用户需要重新上电。 原因 确认方法 处理措施 变更了再次通电后更改生效的功能码 确认是否更改了“生效时间”为“重新上电…

PLC拉格朗日插值(SCL、ST计算源代码)

插值是对函数进行近似的基本方法,这篇博客主要介绍常用的拉格朗日插值法, Lagrange插值法不太清楚的同学,可以看看数值计算和分析类书籍,网上有很多C语言的拉格朗日插值算法,这里我们主要给出在PLC里利用ST,SCL语言完成拉格朗日插值计算。 1、拉格朗日插值FC 插值法可以…

状态模式——对象状态及其转换

1、简介 1.1、概述 在软件系统中&#xff0c;有些对象也像水一样具有多种状态&#xff0c;这些状态在某些情况下能够相互转换&#xff0c;而且对象在不同的状态下也将具有不同的行为。为了更好地对这些具有多种状态的对象进行设计&#xff0c;可以使用一种被称为状态模式的设…

如何把pdf转成cad版本?这种转换方法非常简单

将PDF转换成CAD格式的优势在于&#xff0c;CAD格式通常是用于工程设计和绘图的标准格式。这种格式的文件可以在计算机上进行编辑和修改&#xff0c;而不需要纸质副本。此外&#xff0c;CAD文件通常可以与其他CAD软件进行交互&#xff0c;从而使得工程设计和绘图过程更加高效和精…

fetch-github-hosts间隔一年大更新v2.6发布,多端支持

前言 fetch-github-hosts是一款同步 github hosts 的工具&#xff0c;用于帮助您解决github时而无法访问的问题。在间隔了一年之久的时间&#xff0c;最近抽空将fetch-github-hosts的依赖及UI进行了一波大更新&#xff0c;同时也增加了一些实用的功能。 主要更新 更新了基础依…

安全渗透知识总结二

目录 一、html实体编码 1、Unicode字符编码 2、字符的数字表示 3、常见实体编码 4、url 协议 主机 http状态码 http常用的状态码 端口 常见协议端口 查询参数 锚点 url字符 urlcode字符 绝对url和相对url 二、字符编码 Ascll字符集 html字符集 html的url编码 …

thinkphp8.0多应用模式下提示控制器不存在

thinkphp 8.0 开启多应用模式 1、按照官方文档说明 &#xff0c;已经安装了 think-multi-app composer require topthink/think-multi-app 2、控制器的命名空间也没写错。 3、访问路径与目录名、控制器、方法名一样&#xff0c;访问地址是没错的。 4、网上有说&#xff0c;在…

ubuntu调整路由顺序

Ubuntu系统跳转路由顺序 1、安装ifmetric sudo apt install ifmetric2、查看路由 route -n3、把Iface下面的eth1调到第一位 sudo ifmetric eth1 0命令中eth1是网卡的名称&#xff0c;更改网卡eth1的跃点数&#xff08;metric值&#xff09;为0&#xff08;数值越小&#xf…

Java实现Google授权登录,OAuth 2.0登录

首先创建OAuth 2.0 客户端 ID 配置url&#xff0c;必须是https的&#xff0c;同时复制好客户端id 和密钥 配置回调url /*** Google授权登录跳转。但是会重定向&#xff0c;建议前端跳转** 前端js* // 构建 Google 授权 URL* const authParams new URLSearchParams({* resp…

java linq多字段排序时间比较

public static void main(String[] args) {//100万条数据List<CrmInvestSaleUserCount> waitAssignUserList new ArrayList<>();for (int i 0; i < 1000000; i) {waitAssignUserList.add(new CrmInvestSaleUserCount().setSales_username("test" i…

单元测试之 - Spring框架提供的单元/集成测试注解

Spring框架提供了很多注解来辅助完成单元测试和集成测试(备注&#xff1a;这里的集成测试指容器内部的集成测试&#xff0c;非系统间的集成测试)&#xff0c;先看看Spring框架提供了哪些注解以及对应的作用。RunWith(SpringRunner.class) / ExtendWith(SpringExtension.class)&…

KepwareEX配置API REST接口

服务端Kepware设置 API允许连接设置 创建通道 请求地址(POST)&#xff1a; https://<主机名_或_ip>:<端口>/config/v1/project/channels 以下示例使用postman工具访问API创建了一个名为Channel1 的通道&#xff0c;其使用在本地主机运行的服务器中的Simulator …

VSCode如何在行内显示变量值

背景 在调试时&#xff0c;我们希望能够直接在代码行显示变量的值&#xff0c;而不是总是去侧边栏查看&#xff0c;如下这种&#xff0c;y12直接显示在代码行。那么VSCode中如何做呢 设置 VSCode提供了“inline values”设置&#xff0c;但为了速度&#xff0c;默认并没有开…

Python3 网络爬虫开发实战

第二章 基本库的使用 urlib的使用 比较好用的是parse模块来进行URL的各种处理&#xff0c; requests的使用 requests库也可以session维持&#xff0c;srequests.Session(),s.get(url‘…’) 有些网站没有设置好HTTPS证书&#xff0c;导致出现不是私密连接的错误&#xff0c…