当前位置: 首页 > news >正文

手敲单链表,简单了解其运行逻辑

1. 链表

        1.1 结构组成

        链表是一种物理存储结构上非连续存储结构数据元素的逻辑顺序是通过链表中的引用链接次序实现的

        链表的结构如下图所示,是由很多个节点相互通过引用来连接而成的;每一个节点由两部分组成,分别数据域(存放当前节点的数据)和next域(用来存放连接下一个节点的引用);

                    

        下图是链表的结构,每一个节点都有一个地址,方便前一个节点的next域来存放。多个节点通过引用连接成整个链表。

         实际在内存中每个节点的地址是随机的,只不过用这个节点的next,找到了下一个节点的地址,由此实现链接。

1.2 链表分类

        主要通过链表方向,是否循环,是否带箭头主要分为以下六个特色;

         

        下面是一些不同种类的链表图解:

        1. 单向或者双向

                      

         2. 带头或者不带头

                                 

        3. 循环或者非循环 

                             

        将以上六种单一种类进行组合可以构成一下8种链表

        虽然有这么多的链表的结构,但是我们重点掌握两种:

        无头单向非循环链表:结构简单,一般不会单独用来存数据

        无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。 

2.无头单向非循环链表的实现

2.1 自定义MySingleList类

       建立一个Ilist接口,在里面构造mysinglelist链表要实现的抽象方法;

public interface IList {//头插法void addFirst(int data);//尾插法void addLast(int data);//任意位置插入,第一个数据节点为0号下标void addIndex(int index,int data);//查找是否包含关键字key是否在单链表当中boolean contains(int key);//删除第一次出现关键字为key的节点void remove(int key);//删除所有值为key的节点void removeAllKey(int key);//得到单链表的长度int size();void clear();void display();
}

        无头单向非循环链表的节点是由两个属性(value域和next域构成的),同时也要在自定义MySingleList类里面使用内部类创建链表节点类,之后再链表类里面创建一个头结点来代表当前链表的引用;同时实现我们之前创建的接口,接下来重写接口里面的方法,让其能够具体化;

public class MySingleList implements IList {//创建链表节点//节点的内部类static class ListNode{public int value;public ListNode next;//表示下一个节点的引用public ListNode(int value){this.value = value;}}public ListNode head;@Overridepublic void addFirst(int data) {}@Overridepublic void addLast(int data) {}@Overridepublic void addIndex(int index, int data) {}@Overridepublic boolean contains(int key) {return false;}@Overridepublic void remove(int key) {}@Overridepublic void removeAllKey(int key) {}@Overridepublic int size() {return 0;}@Overridepublic void clear() {}@Overridepublic void display() {}
}
}

        下面代码主要是创建多个节点 

public void createList() {ListNode node1 = new ListNode(12);ListNode node2 = new ListNode(23);ListNode node3 = new ListNode(34);ListNode node4 = new ListNode(45);ListNode node5 = new ListNode(56);node1.next = node2;node2.next = node3;node3.next = node4;node4.next = node5;this.head = node1;}

2.2 遍历链表

        思路:

        1、当前节点是怎么走到下一个节点的

        2、当遍历链表时,如何判断当前链表的所有节点都遍历完

         首先建立一个当前节点cur,通过cur来指向next域里面的节点地址并访问和输出操作来完成整个链表的遍历;让cur的next域指向(存放)下一个节点的地址并访问,以此类推逐步完成整个链表的遍历(问题一);如果cur指向的下一个节点的next域里存放的不是地址,而是空指针,则当前的链表被遍历即将结束(问题二);

        下面是重写的遍历链表具体的方法:

 @Overridepublic void display() {ListNode cur = head;while (cur != null){System.out.print(cur.value+"->");cur = cur.next;}System.out.println(" ");}
 public static void main(String[] args) {MySingleList list = new MySingleList();list.createList();list.display();}

        下面代码的执行结果:

2.3 得到单链表的长度

        对整个链表进行遍历,使用计数器进行记录遍历的次数,最后将计数器的值返回即可,下图代码是该方法的具体实现;

 @Overridepublic int size() {int count = 0;ListNode cur = head;while (cur != null){count++;cur = cur.next;}return count;}
public static void main(String[] args) {MySingleList list = new MySingleList();list.createList();list.display();System.out.println(list.size());}

        下面代码的执行结果:

 2.4 查找是否包含关键字

        对链表进行遍历,然后将关键字key和链表数值进行比较,如果存在key关键字则返回true;反之则返回false;

        方法具体实现的代码如下:

 @Overridepublic boolean contains(int key) {ListNode cur = this.head;while (cur != null){if ( cur.value==key){return true;}cur = cur.next;}return false;}

        测试代码和执行结果如下:

public static void main(String[] args) {MySingleList list = new MySingleList();list.createList();list.display();System.out.println(list.contains(45));}

           

2.5头插法

        思路:

        1、将之前第一个节点的地址存储到我们新添加的节点的next域里面;

        2、将新添加的节点赋给head,作为新链表的头节点,链表图解如下图所示:

        具体实现头插法的方法如下:

@Overridepublic void addFirst(int data) {ListNode node = new ListNode(data);if (this.head == null){this.head = node;}else {node.next = this.head;this.head= node;}

        测试代码及结果:

public static void main(String[] args) {MySingleList list = new MySingleList();list.createList();list.display();list.addFirst(1);list.addFirst(0);list.display();}

          

 2.6尾插法

        思路:

        1、首先对该链表进行遍历,当遍历到最后一个节点时,将新添加的节点的地址给最后一个节点的next域。

        2、如果该链表为空,直接将该新增节点设为头节点

        链表图解:

        具体实现方法带吗如下:

    @Overridepublic void addLast(int data) {ListNode node = new ListNode(data);ListNode cur = this.head;if (this.head == null){this.head = node;}else {//一直找最后一个节点while (cur.next != null){cur = cur.next;}cur.next = node;}}

          测试代码及结果:

public static void main(String[] args) {MySingleList list = new MySingleList();list.createList();list.display();list.addLast(9);list.addLast(10);list.display();}

        分析总结:

        1、头插法的时间复杂度为o(1);尾插法的时间复杂度为o(N);

        2、见下面代码分析

2.7任意位置插入

        思路:

        1、需要插入的位置必须为合法,如果不合法,我们会抛出一个异常进行提醒,所以首先自定义一个异常;

public class ListIndexOutOfException extends RuntimeException{public ListIndexOutOfException(String msg){super(msg);}
}

        2、任意位置插入,首先分几种情况,插在开头,插在结尾,插在中间

        2.1 当插在链表开头和结尾时,可以使用头插法和尾差法;

        2.2 当插在其他的位置时,首先让cur走到index前面一个节点的位置(此处创建一个方法)(这时候就需要考虑将下一个节点加在index的位置时如何处理建立连接的顺序);其次注意建立连接的时候,一定要先建立添加节点和后节点的连接,其次在确立添加节点和前一个节点的位置,链表图解如下:

        具体实现方法代码如下:

 @Overridepublic void addIndex(int index, int data) {if(index < 0 || index > size()) {//抛自定义的异常throw new ListIndexOutOfException("你当前输入的索引有问题");}if(index == 0) {addFirst(data);return;}if(index == size()) {addLast(data);return;}ListNode cur = searchPrev(index);//node之前的一个节点ListNode node = new ListNode(data);node.next = cur.next;cur.next = node;}private ListNode searchPrev(int index) {//该方法是找到添加节点node在index时//index之前的节点的索引ListNode cur = this.head;int count = 0;while (count != index-1 ) {cur = cur.next;count++;}return cur;}

        测试代码及结果如下:

 public static void main(String[] args) {MySingleList list = new MySingleList();list.createList();list.display();list.addIndex(2,2);list.addIndex(3,3);list.display();}

2.8删除第一次出现关键字为key的节点

        思路:大体分为以下四种情况

        1.链表为空链表,一个节点也没有
        2.我们所需要删除数据所在的节点在第一个
        3.遍历完所有的链表节点,发现没有要删除的数据
        4.有要删除的数据且不是第一个节点

        具体实现方法代码如下:

public void remove(int key) {if(this.head == null) {//一个节点都没有 无法删除!return;}if(this.head.value == key) {this.head = this.head.next;return;}//1. 找到前驱ListNode cur = findPrev(key);//2、判断返回值是否为空?if(cur == null) {System.out.println("没有你要删除的数字");return;}//3、删除ListNode del = cur.next;cur.next = del.next;}private ListNode findPrev(int key) {//找到要删除节点的前一个节点ListNode cur = this.head;while (cur.next != null) {if(cur.next.value == key) {return cur;}cur = cur.next;}return null;}

        测试代码及结果如下:

public static void main(String[] args) {MySingleList list = new MySingleList();list.createList();list.display();list.addIndex(2,2);list.addIndex(3,3);list.remove(100);list.display();}

2.9回收链表

        将头节点置为空即可,代码和结果如下所示;

 @Overridepublic void clear() {this.head = null;}

 

ps:本次的内容就到这里了,如果你喜欢的话,就请一键三连哦!!!

        

      

相关文章:

手敲单链表,简单了解其运行逻辑

1. 链表 1.1 结构组成 链表是一种物理存储结构上非连续存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。 链表的结构如下图所示&#xff0c;是由很多个节点相互通过引用来连接而成的&#xff1b;每一个节点由两部分组成&#xff0c;分别数据域&…...

Redis RDB

基于内存的 Redis, 数据都是存储在内存中的。 那么如果重启的话, 数据就会丢失。 为了解决这个问题, Redis 提供了 2 种数据持久化的方案: RDB 和 AOF。 RDB 是 Redis 默认的持久化方案。当满足一定条件的时候, 会把当前内存中的数据写入磁盘, 生成一个快照文件 dump.rdb。Redi…...

Elasticsearch一些函数查询

1. 根据价格分组统计数量&#xff0c;每组区间为2000&#xff0c; filter_pathaggregations 设置查询结果只展示函数结果 也有date_histogram函数根据日期分组等等 GET order/_search?filter_pathaggregations {"aggs": {"hist_price": {"histogr…...

竞赛选题 : 题目:基于深度学习的水果识别 设计 开题 技术

1 前言 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天做一个 基于深度学习的水果识别demo 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/pos…...

Linux expect命令详解

在Linux系统中&#xff0c;expect 是一款非常有用的工具&#xff0c;它允许用户自动化与需要用户输入进行交互的程序。本文将深入探讨expect命令的基本语法、使用方法以及一些最佳实践。 什么是Expect命令&#xff1f; expect 是一个用于自动化交互式进程的工具。它的主要功能…...

ubuntu18编译Android8的Failed to contact Jack server问题

环境 ubuntu18.04 Android8.1.0 步骤 安装环境 apt install git-core apt install gnupg apt install flex apt install bison apt install gperf apt install build-essential apt install curl apt install libc6-dev apt install libssl-dev apt install libncurses5-dev:…...

FindSecBugs支持的检测规则

很多SAST集成了FindSecBugs这个开源工具&#xff0c;其好处是直接对Class文件进行检测&#xff0c;也就是直接检测二进制问题&#xff0c;可以直接检测war、jar&#xff0c;还是非常方便的。虽然误报率较高&#xff0c;但是这些检测出来的安全漏洞很多是安全从业人员耳熟能详的…...

【WPF.NET开发】WPF.NET桌面应用开发概述

本文内容 为何从 .NET Framework 升级使用 WPF 进行编程标记和代码隐藏输入和命令控件布局数据绑定图形和动画文本和版式自定义 WPF 应用 Windows Presentation Foundation (WPF) 是一个与分辨率无关的 UI 框架&#xff0c;使用基于矢量的呈现引擎&#xff0c;构建用于利用现…...

态势感知是什么

在当今高度信息化的时代&#xff0c;信息安全风险已经成为企业、政府和个人的重要关注点。为了有效应对这些风险&#xff0c;态势感知成为了一种日益重要的能力。态势感知是一种基于环境的、动态、整体地洞悉安全风险的能力&#xff0c;是以安全大数据为基础&#xff0c;从全局…...

Spring MVC常用的注解, Controller注解的作用,RequestMapping注解的作用 @ResponseBody注解的作用

文章目录 Spring MVC常用的注解和注解的相关作用Controller注解的作用RequestMapping注解的作用ResponseBody注解的作用PathVariable和RequestParam的区别 Spring MVC常用的注解和注解的相关作用 RequestMapping&#xff1a;用于处理请求 url 映射的注解&#xff0c;可用于类或…...

「Verilog学习笔记」自动贩售机1

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 自动贩售机中可能存在的几种金额&#xff1a;0&#xff0c;0.5&#xff0c;1&#xff0c;1.5&#xff0c;2&#xff0c;2.5&#xff0c;3。然后直接将其作为状态机的几种状…...

【大模型】更强的 ChatGLM3-6B 来了,开源可商用

【大模型】更强的 ChatGLM3-6B 来了&#xff0c;开源可商用 简介ChatGLM3-6B 环境配置环境搭建安装依赖 代码及模型权重拉取拉取 ChatGLM3-6B拉取 ChatGLM3-6B 模型权重及代码 终端测试网页测试安装 gradio加载模型并启动服务 参考 简介 ChatGLM3-6B ChatGLM3-6B 是 ChatGLM …...

Maxscript到Python转换工具教程

Maxscript到Python转换器教程 Maxscript到Python转换器采用MAXScript程序&#xff0c;将其解析为语法树&#xff0c;然后从语法树中生成等效的Python代码。通过提供python的自动翻译&#xff0c;帮助python程序员理解maxscript示例。 【项目状况】 将正确解析最正确的maxcript…...

Spark_日期参数解析参数-spark.sql.legacy.timeParserPolicy

在Apache Spark中&#xff0c;spark.sql.legacy.timeParserPolicy是一个配置选项&#xff0c;它控制着时间和日期解析策略。此选项主要影响如何解析日期和时间字符串。 在Spark 3.0之前的版本中&#xff0c;日期和时间解析使用java.text.SimpleDateFormat&#xff0c;它在解析…...

C语言之结构体

一.前言引入. 我们知道在C语言中有内置类型&#xff0c;如&#xff1a;整型&#xff0c;浮点型等。但是只有这些内置类 型还是不够的&#xff0c;假设我想描述学⽣&#xff0c;描述⼀本书&#xff0c;这时单⼀的内置类型是不⾏的。描述⼀个学⽣需要名字、年龄、学号、⾝⾼、体…...

【蓝桥杯软件赛 零基础备赛20周】第5周——高精度大数运算与队列

文章目录 1. 数组的应用–高精度大数运算1.1 Java和Python计算大数1.2 C/C高精度计算大数1.2.1 高精度加法1.2.2 高精度减法 2. 队列2.1 手写队列2.1.1 C/C手写队列2.1.2 Java手写队列2.1.3 Python手写队列 2.2 C STL队列queue2.3 Java队列Queue2.4 Python队列Queue和deque2.5 …...

C#:程序发布的大小控制

.net不讨喜有个大原因就是.net平台本身太大了&#xff0c;不同版本没有兼容性&#xff0c;程序依赖哪个版本用户就要安装哪个版本&#xff0c;除非你恰好用的是操作系统默认安装的版本——问题是不同版本操作系统默认安装的不一样。 所以打包程序就很头疼&#xff0c;不打包平台…...

Python中的split()、rsplit()、splitlines()的区别

split、rsplit、splitlines的区别 1、split()2、rsplit()3、splitlines() Python提供了三种字符串分割的方法&#xff1a;split()、rsplit()和splitlines()&#xff1b;本文主要通过案例介绍这三种字符串分割函数的区别 1、split() split()主要用于从左向右匹配分割符进行分割…...

上位机开发框架:QT与winform/wpf对比

QT QT 是一个跨平台的 C 应用程序框架&#xff0c;它提供了丰富的 UI 组件和功能强大的网络通信、数据库操作等模块。QT 的优势在于其良好的跨平台性能&#xff0c;可以方便地部署在 Windows、Linux、macOS 等不同操作系统上。此外&#xff0c;QT 还具有强大的 UI 设计能力&am…...

Halcon tiff 点云读取以及平面矫正

一、读取tiff 图 dev_close_window () dev_open_window (0, 0, 512, 512, black, WindowHandle)xResolution:0.0025 yResolution:0.0025 zResolution:0.001 read_image (IntputImage, C:/Users/alber/Desktop/2023-08-15_16-38-24-982_/Sta5_002.tif) zoom_image_factor (Intpu…...

详解Spring中基于注解的Aop编程以及Spring对于JDK和CGLIB代理方式的切换

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…...

百度/抖音/小红书/微信搜索品牌形象优化怎么做?

搜索口碑是网络营销不可或缺的一部分&#xff0c;企业如何做好品牌搜索口碑优化呢&#xff1f;小马识途营销顾问建议从以下几方面入手。 1. 通过关键字优化提高自身知名度 通过对竞争对手和目标客户的关键字进行分析&#xff0c;企业可以确定哪些关键字可以提高自身品牌知名度。…...

爬虫学习(三)用beautiful 解析html

安装库 import requests from bs4 import BeautifulSoup headers {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"} for start_num in range(0,250…...

OSG编程指南<十四>:OSG纹理渲染之普通纹理、多重纹理、Mipmap多级渐远纹理及TextureRectangle矩阵纹理

1、纹理映射介绍 物体的外观不仅包括形状&#xff0c;不同物体表面有着不同的颜色和图案。一个简单而有效地实现这种特性的方法就是使用纹理映射。在三维图形中&#xff0c;纹理映射&#xff08;Texture Mapping&#xff09;的方法运用广泛&#xff0c;使用该技术可以大大提高物…...

Langchain-Chatchat的安装过程

参考&#xff1a;LLMs之RAG&#xff1a;LangChain-Chatchat(一款中文友好的全流程本地知识库问答应用)的简介(支持 FastChat 接入的ChatGLM-2/LLaMA-2等多款主流LLMs多款embe_一个处女座的程序猿的博客-CSDN博客 1、安装过程中出现了 GPU驱动版本 是11.8 而 python -c "…...

Windows系列:Windows Server 2012 R2 安装VMware Tools的正确姿势(实现物理机和虚拟机文件互传)

Windows Server 2012 R2 安装VMware Tools的正确姿势(实现物理机和虚拟机文件互传) 安装环境安装步骤一. 安装补丁下面进入教程首先打开虚拟机,点击"虚拟机"选项中的"安装VMware Tools"点击确定如果出现下图中的问题,说明虚拟机中缺少更新程序,我们需…...

最长连续递增序列

最长连续递增序列 描述 : 给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 连续递增的子序列 可以由两个下标 l 和 r&#xff08;l < r&#xff09;确定&#xff0c;如果对于每个 l < i < r&#xff0c;都有 …...

FreeRTOS入门--任务

目录 一、什么是任务 二、创建任务---xTaskCreate函数 三、任务的删除 四、任务优先级 1.阻塞状态(Blocked) 2.暂停状态(Suspended) 3.就绪状态(Ready) 五、Delay 六、调度算法 一、什么是任务 在FreeRTOS中&#xff0c;任务就是一个函数&#xff0c;原型如下&#xff…...

4个解决特定的任务的Pandas高效代码

在本文中&#xff0c;我将分享4个在一行代码中完成的Pandas操作。这些操作可以有效地解决特定的任务&#xff0c;并以一种好的方式给出结果。 从列表中创建字典 我有一份商品清单&#xff0c;我想看看它们的分布情况。更具体地说&#xff1a;希望得到唯一值以及它们在列表中出…...

【已解决】AttributeError: module ‘gradio‘ has no attribute ‘Image‘

问题描述 AttributeError: module gradio has no attribute Image 不知道作者用的是哪个gradio版本&#xff0c;最新的版本报错AttributeError: module gradio has no attribute outputs &#xff0c; 换一个老一点的版本会报错AttributeError: module gradio has no attribute…...