Java 数据结构篇-实现单链表核心API

news2024/11/28 14:41:19

🔥博客主页: 小扳_-CSDN博客
❤感谢大家点赞👍收藏⭐评论✍
   

 

 

文章目录

        1.0 单链表的说明

        2.0 单链表的创建

        2.1 单链表 - 头插节点

        2.2 单链表 - 遍历

        2.2.1 使用简单的 for/while 循环

        2.2.2 实现 forEach 方法

        2.2.3 实现迭代器的方法

        2.3 单链表 - 尾插节点

        2.4 单链表 - 通过索引获取数据

        2.5 单链表 - 通过索引插入数据

        2.6 单链表 - 头删节点

        2.7 单链表 - 根据节点来删除数据

         3.0 实现单链表的完整代码


        1.0 单链表的说明

        单链表是一种数据结构。数据结构是指数据的组织、管理和存储的方式,而单链表是一种常见的线性数据结构,用于存储一系列具有相同类型的元素。它由一系列节点组成每个节点包含一个数据元素和一个指向下一个节点的指针。单链表可以通过指针的方式实现元素的插入、删除和查找等操作。

        2.0 单链表的创建

       把单链表封装成一个类,面向对象编程的思路。类中需要的成员变量为头节点节点,又可以把节点封装成一个类,为更好把节点类封装起来,将其设置为静态内部类

代码如下:

public class SingleLists{
    //头节点
    private Node hand = null;


    //节点
    private static class Node {
        //数据
        private int data;
        //指向下一个节点
        private Node next;

        public Node() {
        }

}

        注意的是,这些成员都不会对外访问的,所以需要把成员变为私有成员

        2.1 单链表 - 头插节点

       顾名思义,就是在头节点处插入新的节点,使其成为新的头节点。需要考虑两种情况,第一种情况,头节点为 null 时,直接就可以将创建出来的对象被 hand 引用了。第二种情况,头节点不为 null 时,需要将创建的对象的 next 引用指向 hand 的引用,而当前创建的对象就要被 hand 引用。

代码如下:

    //实现头插节点
    public void addFirst(int data) {
/*        if (hand == null){
            hand = new Node(data,null);
        }else {
            hand = new Node(data,hand);
        }*/
        
        //对以上代码进行简化得以下代码:
        hand = new Node(data,hand);
        
    }

        需要注意的时,该 API 是对外访问。

        2.2 单链表 - 遍历

        实现遍历的方式有三种:

        第一种方式,使用简单的 for/while 循环。

        第二种方式,实现 forEach 方法。

        第三种方式,实现迭代器的方法。

        2.2.1 使用简单的 for/while 循环

        一般 hand 是不会去移动或者去改变其引用,则需要临时的变量 p 来指向 hand 的对象。循环的条件为 p != null,每一次循环结束都需要 p 去移动到下一个节点处,p = p.next

代码如下:

    //遍历方式:打印方式
    public void myPrint(){
        if (hand == null){
            throw new RuntimeException("hand is null!!!!");
        }
        //第一种:
/*        Node p = hand;
        //用while来实现
        while (p != null){
            System.out.println(p.data);
            p = p.next;
        }*/
        //第二种:
        //用for来实现
        for (Node p = hand;p !=null;p = p.next){
            System.out.println(p.data);
        }
    }

        还需要注意,for 与 while 这两种的实现逻辑是一样的,假如 hand 的引用为空,则没必要去循环了,直接去抛出错误。

        2.2.2 实现 forEach 方法

        对于 for/while 的遍历方法直接把 “方法写死了”,forEeach 方法是对 for/while 的方法进行了升级。参数为 Consumer<Integer> 内部类,再重写 accept 方法。

代码如下:

    //遍历方式:实现forEach,由于跟以下的代码有冲突,先改名为 myForEach。
    public void myForEach(Consumer<Integer> consumer){
        for (Node p = hand; p != null;p = p.next){
            consumer.accept(p.data);
        }
    }

具体调用该方法的使用:

        singleLists.myForEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
            }
        });

        这样对外获取的数据可以自由支配使用,不仅仅打印输出了。

        2.2.3 实现迭代器的方法

        需要实现接口 Iterable<Integer> ,该接口支持泛型,目前先实现整数类型的单链表。重写 hasNext()next() 方法。

代码如下:

    //遍历方式:使用迭代器循环
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            Node p = hand;
            @Override
            public boolean hasNext() {
                return p != null;
            }

            @Override
            public Integer next() {
                int k = p.data;
                p = p.next;
                return k;
            }
        };

        重写完的 hasNext() 这个方法的作用:是判断当前 p 是否为 null ,如果是就停止遍历,结束了。反之继续遍历下去。

        重写之后的 next() 方法的作用:做了两个动作,第一个动作就是获取当前的数据;第二个动作就是将 p 移向下一个节点。

具体调用该方法的使用:

        for (Integer value:singleLists) {
            System.out.println(value);
        }

        同理,这个方式不仅仅只有打印输出了,自由支配使用。

        2.3 单链表 - 尾插节点

        找最后的节点后面插入新的节点,如果只有头节点,需要不断的遍历,直到最后一个节点。遍历的条件为 p.next != null,跟以上的条件需要区别开来,这里需要得到最后的节点,可不能 p !=null 一直下去,这样就会找不到最后的节点。

代码如下:

    //尾插节点
    public void addLast(int data) {
        if (hand == null) {
            addFirst(data);
            return;
        }
        Node p = hand;
        while (p.next != null){
            p = p.next;
        }
        p.next = new Node(data,null);
    }

        需要注意的是,单独分开当 hand 为 null 时,因为 hand.next == null 了,但是对于hand 为 null 时也可以插入节点呀,所以 当 hand 为 null 时,可以调用头插节点的方法。

        2.4 单链表 - 通过索引获取数据

        单链表是不连续的,不用直接通过索引来访问节点去读取数据,因此,先独立设置一个方法,需设置一个 i 记数点,每一个遍历完 i++ ,直到 i == index 时,先返回该节点。再独立另一个方法,通过该节点来读取该数据。

代码如下:

    //根据索引获取某个节点
    private Node findNode(int index) {
        int i = 0;
        for (Node p = hand ; p != null ; p = p.next,i++)
        {
            if (i == index) {
                return p;
            }
        }
        return null;
    }



    //根据索引得到对应的数据
    public int get(int index) {
        Node p = findNode(index);
        if (p == null){
            throw new RuntimeException("找不到该索引!!!");
        }
        return p.data;
    }

        对于找不到的节点,需要抛出异常,需要注意的是,findNode 方法是不对外访问的,需要封装起来。

        2.5 单链表 - 通过索引插入数据

        先获取插入位置的前一个 prev 节点,然后 prev.next 去指向插入的节点的对象,插入节点的 next 去引用原先 prev.next 的对象。

代码如下:

    //根据索引插入数据
    public void insert(int index , int data){
        if (index == 0){
            addFirst(data);
        }
        Node prev = findNode(index - 1);
        if (prev == null){
            throw new RuntimeException("index is illegal");
        }
        prev.next =  new Node(data,prev.next);
    }

         需要注意的是,先判断插入点是否为头节点,如果是头节点,则调用头插的方法。再去判断其他情况通过 findNode() 方法是否得到 null,如果是,需要抛出异常。

        2.6 单链表 - 头删节点

        顾名思义直接删除头节点,思路为: hand 这个引用需要指向 hand.next ,这就是删除了第一个节点,没用引用的对象,在 Java 中回自动回收的,不会占内存,这也就是删除了。

代码如下:

    //头删节点
    public void removeFirst() {
        if (hand == null){
            throw new RuntimeException("There are no nodes anymore");
        }
        hand = hand.next;
    }

        需要注意,删除前先判断 hand 是否为 null 。

        2.7 单链表 - 根据节点来删除数据

        先找到要删除节点的前一个 prev 节点,然后再去找到 要删除的节点 move = prev.next ,接着将 prev.next = move.next 即可。

代码如下:

    //根据索引来删除节点
    public void remove(int index) {
        if (index == 0) {
            removeFirst();
            return;
        }
        Node prev = findNode(index - 1);
        if (prev == null){
            throw new RuntimeException("There are no nodes anymore");
        }
        Node move = prev.next;
        if (move == null) {
            throw new RuntimeException("There are no nodes anymore");
        }
        prev.next = move.next;
    }

        在删除节点的时候需要先判断 index 是否为 0,如果是,则调用头删的方法,再通过 findNode() 方法来找到删除节点的前一个节点,如果得到的节点为 null,则需要抛出异常,同样的如果得到的需要删除的节点为 null ,则需要抛出异常。

         3.0 实现单链表的完整代码


import java.util.Iterator;
import java.util.function.Consumer;

//整体
public class SingleLists implements Iterable<Integer>{
    //头节点
    private Node hand = null;


    //节点
    private static class Node {
        //数据
        private int data;
        //指向下一个节点
        private Node next;

        public Node() {
        }

        public Node(int data, Node next) {
            this.data = data;
            this.next = next;
        }
    }

    //实现头插节点
    public void addFirst(int data) {
/*        if (hand == null){
            hand = new Node(data,null);
        }else {
            hand = new Node(data,hand);
        }*/

        //对以上代码进行简化得以下代码:
        hand = new Node(data,hand);

    }

    //遍历方式:打印方式
    public void myPrint(){
        if (hand == null){
            throw new RuntimeException("hand is null!!!!");
        }
        //第一种:
/*        Node p = hand;
        //用while来实现
        while (p != null){
            System.out.println(p.data);
            p = p.next;
        }*/
        //第二种:
        //用for来实现
        for (Node p = hand;p !=null;p = p.next){
            System.out.println(p.data);
        }
    }

    //遍历方式:实现forEach,由于跟以下的代码有冲突,先改名为 myForEach。
    public void myForEach(Consumer<Integer> consumer){
        for (Node p = hand; p != null;p = p.next){
            consumer.accept(p.data);
        }
    }

    //遍历方式:使用迭代器循环
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            Node p = hand;
            @Override
            public boolean hasNext() {
                return p != null;
            }

            @Override
            public Integer next() {
                int k = p.data;
                p = p.next;
                return k;
            }
        };
    }

    //尾插节点
    public void addLast(int data) {
        if (hand == null) {
            addFirst(data);
            return;
        }
        Node p = hand;
        while (p.next != null){
            p = p.next;
        }
        p.next = new Node(data,null);
    }

    //根据索引获取某个节点
    private Node findNode(int index) {
        int i = 0;
        for (Node p = hand ; p != null ; p = p.next,i++)
        {
            if (i == index) {
                return p;
            }
        }
        return null;
    }

    //根据索引得到对应的数据
    public int get(int index) {
        Node p = findNode(index);
        if (p == null){
            throw new RuntimeException("找不到该索引!!!");
        }
        return p.data;
    }

    //根据索引插入数据
    public void insert(int index , int data){
        if (index == 0){
            addFirst(data);
        }
        Node prev = findNode(index - 1);
        if (prev == null){
            throw new RuntimeException("index is illegal");
        }
        prev.next =  new Node(data,prev.next);
    }

    //头删节点
    public void removeFirst() {
        if (hand == null){
            throw new RuntimeException("There are no nodes anymore");
        }
        hand = hand.next;
    }

    //根据索引来删除节点
    public void remove(int index) {
        if (index == 0) {
            removeFirst();
            return;
        }
        Node prev = findNode(index - 1);
        if (prev == null){
            throw new RuntimeException("There are no nodes anymore");
        }
        Node move = prev.next;
        if (move == null) {
            throw new RuntimeException("There are no nodes anymore");
        }
        prev.next = move.next;
    }


}

 

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

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

相关文章

使用腾讯云服务器建站流程(新手站长指南)

使用腾讯云服务器搭建网站全流程&#xff0c;包括轻量应用服务器和云服务器CVM建站教程&#xff0c;轻量可以使用应用镜像一键建站&#xff0c;云服务器CVM可以通过安装宝塔面板的方式来搭建网站&#xff0c;腾讯云服务器网txyfwq.com分享使用腾讯云服务器建站教程&#xff0c;…

【网络协议】聊聊CND如何进行提升系统读性能

我们知道对于京东这种仓储来说&#xff0c;其实并不是在北京有一个仓储中心&#xff0c;而是针对全国主要的地方&#xff0c;北京、上海、广州、杭州&#xff0c;郑州等地方都有自己的仓储中心&#xff0c;当用户下单后&#xff0c;就会根据最近的仓储进行发货&#xff0c;不仅…

第二章:input partitioning

文章目录 Input partitioninginput partitioning 的目的computational / domain faults等价类&#xff08;equivalence classes&#xff09;input conditions & valid / invalid inputspartitioning and equivalence classes等价类划分的原则 白盒 - Domain testing复合谓词…

curl(七)上传和下载

一 上传 ① -T | --upload 上传 ​1、向ftp服务器 传一个文件&#xff1a;curl -T localfile -u name&#xff1a;passwd ftp://upload_site&#xff1a;port/path/2、向http服务器上传文件curl -T localfile http://www.wzj.com/wzj.html注意: 这时候使用的协议是HTTP的PUT…

全球首款双模型AI手机METAVERTU2,为用户开发“第二大脑”

在2023年11月1日&#xff0c;英国奢侈手机品牌VERTU在香港举办了一场新品发布会&#xff0c;它推出了一款全新的AI手机称为METAVERTU2&#xff0c;这是全球首款双模型AI手机。此款手机将Web3技术与人工智能相结合&#xff0c;通过AI模型标记数据和AI Agent的方式&#xff0c;将…

在线安装Arthas以及常用命令介绍

Arthas介绍&#xff1a;arthas(阿尔萨斯)是阿里巴巴开源的一款 Java 诊断工具&#xff0c;它可以对运行中的 Java 程序进行实时监控和故障排查。Arthas 提供了丰富的功能&#xff0c;如线程分析、内存分析、类加载分析等&#xff0c;帮助开发者快速定位问题并提高开发效率。 主…

自动控制原理答案

题目 现有一个单位反馈系统的开环传递函数为 试对该系统进行以下分析。 1.基础分析 计算该系统的闭环传递函数。 2.稳定性分析 2.1 使用劳斯判据分析该系统的稳定性 2.2 使用MATLAB编程&#xff0c;计算该系统有关于稳定性分析的零、极点&#xff0c;分析其稳定性。 3.暂态性…

性能测试知多少---吞吐量

我们每天的生活中都在用水用电&#xff0c;我只会关心自己的水管是否有水&#xff0c;水压是否稳定&#xff0c;如果我们把水龙头拧到最大&#xff0c;还是一滴一滴的流水。那我们就要愤怒了&#xff0c;直接找房东问明情况。我们从来没想过去找自来水公司。我们每天都会上网&a…

【原创】java+swing+mysql宠物领养管理系统设计与实现

摘要&#xff1a; 生活中&#xff0c;有很多被人遗弃的宠物&#xff0c;这些宠物的处理成为了一个新的难题。生活中也有许多人喜欢养宠物&#xff0c;为了方便大家进行宠物领养&#xff0c;提高宠物领养管理的效率和便利性。本文针对这一问题&#xff0c;提出设计和实现一个基…

Matlab上机三(Apriori算法)

1、题目要求 &#xff08;1&#xff09; 读取给定的交易数据库test3.txt&#xff0c;将整个交易数据库表示为一个矩阵&#xff0c;每个元组表示成一个行向量&#xff0c;向量长度为4。其中&#xff0c;一个项目出现在这个元组中&#xff0c;则相应位置设为1&#xff0c;否则为…

比亚迪被曝 24 小时收到 12 万份简历?

众所周知&#xff0c;今年找工作的难度都相当大&#xff0c;不论是应届毕业生还是经验丰富的职场人士&#xff0c;都面临相同的困境。然而&#xff0c;没想到情况居然如此糟糕&#xff0c;着实让人震惊。 最近&#xff0c;比亚迪公司被曝收到了12万份简历&#xff0c;简历投递…

深度学习框架TensorFlow.NET环境搭建1(C#)

测试环境 visual studio 2017 window10 64位 测试步骤如下&#xff1a; 1 新建.net framework控制台项目&#xff0c;工程名称为TensorFlowNetDemo&#xff0c;.net framework的版本选4.7.2&#xff0c;如下图&#xff1a; 2 分别安装TensorFlow.NET包(先装)和SciSharp.…

分治法——找众数

分治法——找众数 要求&#xff1a; 寻找整数数组的众数&#xff0c;如果存在多个众数&#xff0c;则返回权值最小的那个 第一步&#xff1a; 要利用分治法找众数&#xff0c;首先就先要使数组有序。这里&#xff0c;我们用C语言库中的qsort进行快排&#xff1a; qsort(nums…

Verilog HDL语言基础知识

目录 Verilog HDL语言基础知识 6.1.2 Verilog HDL模块的结构 6.1.3 逻辑功能定义 6.2.1 常量 6.3 运算符及表达式 6.4.2 条件语句 Verilog HDL语言基础知识 先来看两个Verilog HDL程序。 例6.1 一个8位全加器的 Verilog HDL源代码 module adder8(cout,sum,ina,…

如何用 GPT-4 全模式(All Tools)帮你高效学习和工作?

「十项全能」的 ChatGPT &#xff0c;用起来感受如何&#xff1f; 之前&#xff0c;作为 ChatGPT Plus 用户&#xff0c;如果你集齐下面这五个模式&#xff0c;就会成为别人羡慕的对象。 但现在&#xff0c;人们更加期盼的&#xff0c;是下面这个提示的出现&#xff1a; 这个提…

Python---字符串中的count()方法

count()方法 主要功能&#xff1a;求子串在字符串中出现的次数 count 英 /kaʊnt/ v. &#xff08;按顺序&#xff09;数数&#xff1b;计数&#xff0c;点数目&#xff1b;把……算入&#xff0c;包括&#xff1b;重要&#xff1b;被允许&#xff0c;被接受&#xff1b;…

项目实战:新增@RequestMapping和@GetMapping和@PostMapping三个注解

1、RequestMapping package com.csdn.mymvc.annotation; import java.lang.annotation.*; Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Inherited public interface RequestMapping {String value(); }2、PostMapping package com.csdn.mymvc.annotation; im…

Java自学第5课:Java web开发环境概述,更换Eclipse版本

1 Java web开发环境 前面我们讲了java基本开发环境&#xff0c;但最终还是要转到web来的&#xff0c;先看下怎么搭建开发环境。 这个图就是大概讲了下开发和应用环境&#xff0c;其实很简单&#xff0c;对于一台裸机&#xff0c;win7 系统的&#xff0c;首先第1步&#xff0c;…

Makefile初识

目录 0.前期准备0.1、程序编译链接&#xff1a; 1.Makefile基础1.1、认识Makefile1.2、Makefile定义模式&#xff1a;(1) 定义模式&#xff1a;(2) 执行Makefile&#xff1a; 1.3、Makefile的变量(1) 变量定义&#xff1a;(2) **变量的赋值符**:(3) 自动化变量 1.4 伪目标1.5 文…

【C++】特殊类设计+类型转换+IO流

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…