当前位置: 首页 > 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…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...