数据结构与算法(六)--链表的遍历,查询和修改,删除操作

news2024/11/18 19:35:08

一、前言

上篇文章我们了解了链表的概念以及链表底层的搭建以及向链表中添加元素的操作。本次我们继续学习链表剩余的操作:遍历,查询和修改、删除操作。

二、链表查询以及遍历

①获得链表的第index(0-based)个位置的元素(不常用,仅做练习)

和add不一样的是,add我们是要找到第Index的前一个元素,所以,我们起点从dummyHead开始,然后遍历index次。而get不同,get就是要第Index上的元素,所以我们可以直接从dummyHead.next开始,其实就是"索引"为0的位置开始,遍历index次,这样就可以找到第Index个位置的元素了。

	//获取index索引上的元素
	public T get(int index) {
		if (index < 0 || index >= size) {
			throw new IllegalArgumentException("get failed;index should >= 0 or index < size");
		}
		Node cur = dummyHead.next;
		for (int i = 0; i < index; i++) {
			cur = cur.next;
		}
		return cur.data;
	}

那么同理有了get(),我们就可以添加更方便的一些方法,例如getFirst()和getLast():

    public T getFirst(){
		return get(0);
	}
	public T getLast(){
		return get(size - 1);
	}

②、查找链表中是否有元素e

这个就有点特殊了,因为我们现在不知道具体要在哪个“索引”操作,所以我们需要从头开始遍历
那么我们可以使用for循环,和之前一样,从"索引"为0的位置开始找,然后遍历size次,这种方式是可行的。但是这里呢我们采用while循环来遍历链表,因为这种方式我们后面会用到很多,那么代码非常的简单,如下所示,这其实就是链表的遍历:

	public boolean contains(T t){
		Node cur = dummyHead.next;
		//只要cur不为NULL,其实就是到最后一个节点
		while (cur != null){
			if(cur.data == t){
				return true;
			}
			cur = cur.next;
		}
		return false;
	}

其实用for循环不使用size变量也是可以做到的,思路和上面的while循环大同小异:

for(Node cur = dummyHead.next; cur != null; cur = cur.next){...}

类似的,我们也可以在toString()中去遍历我们的链表:

	@Override
	public String toString(){
		StringBuilder stringBuilder = new StringBuilder();
		Node cur = dummyHead.next;
		while (cur != null){
			stringBuilder.append(cur + "->");
			cur = cur.next;
		}
		stringBuilder.append("NULL");
		return stringBuilder.toString();
	}

三、链表的更新(不常用,仅做练习)

更新操作其实和上面的get操作非常类似,只是将返回元素变为了直接更新,这里不做赘述,代码如下:

	public void set(int index, T t){
		if (index < 0 || index >= size) {
			throw new IllegalArgumentException("get failed;index should >= 0 or index < size");
		}
		Node cur = dummyHead.next;
		for (int i = 0; i < index; i++) {
			cur = cur.next;
		}
		cur.data = t;
	}

四、链表元素的删除

那么有了之前的基础,我们删除元素是很简单的,我们仍然需要用到虚拟头结点。
例如,我想要删除"索引"为2位置上的元素:
在这里插入图片描述
那么对于删除链表元素来说,我们和添加元素是一样的,我们需要找到被删除元素的前一个元素,所以我们仍然需要prev,而prev.next就是我们要删除的节点delNode了:
在这里插入图片描述
然后 我们要做的就是将prev.next = delNode.next:,这样做完之后,我们链表顺着这个next走。1的next就是3,3的next就是4,从某种意义来说等同于将2这个节点删除了。
在这里插入图片描述
当然为了方便我们java回收这个空间,我们应该手动将2这个删除节点的next指向null,delNode.next =null;

然后我们便可以开始进行代码设计了,删除代码非常的简单:

	public T remove(int index){
		if (index < 0 || index >= size) {
			throw new IllegalArgumentException("get failed;index should >= 0 or index < size");
		}
		Node prev = dummyHead;
		for(int i = 0;i<index;i++){
			prev = prev.next;
		}
		Node ret = prev.next;
		prev.next = ret.next;
		ret.next = null;
		size --;
		return ret.data;
	}

那么remove完成后,我们同理可以设计一些方便的remove方法,即removeFirst,removeLast等:

	public T removeFirst(){
		
		return remove(0);
	}	
	
	public T removeLast(){
		return remove(size - 1);
	}

我们可以试试:

	public static void main(String[] args) {
		LinkedList<Integer> integerLinkedList = new LinkedList<>();
		for (int i = 0; i < 5; i++) {
			integerLinkedList.addFirst(i);
			System.out.println(integerLinkedList);
		}
		integerLinkedList.add(666,2);
		System.out.println(integerLinkedList);
		System.out.println(integerLinkedList.remove(2));
		System.out.println(integerLinkedList.removeLast());
		System.out.println(integerLinkedList);
	}

在这里插入图片描述
五、链表的时间复杂度分析

添加操作

  • addLast(e) ----------- O(n)
  • addFirst(e) ---------- O(1)
  • add(index,e) -----------O(n/2)=O(n)

所以综上来看,链表的添加操作是O(n)的

删除操作

  • removeLast(e) ----------- O(n)
  • removeFirst(e) ---------- O(1)
  • remove(index,e) -----------O(n/2)=O(n)

所以综上来看,链表的删除操作也是O(n)的

修改操作

  • set(index,e) -------O(n)

查找操作

  • get(index) ----------- O(n)
  • contains(e) ----------- O(n)

但是如果查询的是链表头元素的时候,此时时间复杂度是O(1)

所以综上来看,链表的查找操作也是O(n)的

那么综上分析,链表的CRUD操作时间复杂度全是O(n)的,确实在时间复杂度的角度上分析,它确实整体不如数组,因为数组具有随机访问的能力,但是链表底层上就不支持。但是我们发现如果只对链表头进行增删操作,时间复杂度均为O(1),所以我们的链表它适合做的事情是不去修改,而对于查也不能去查任意的元素,可以只查链表头的元素.并且在增加和删除的时候,只能对链表头进行操作。且链表本身就是动态的数据结构,是非常节省内存空间的。

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

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

相关文章

微信定时发圈、跟圈是怎么操作的?

对于私域运营来说&#xff0c;手上都会有几个微信账号需要管理运营&#xff0c;每天需发圈、评论等操作都已经占据大量的时间了&#xff0c;更别说分配时间去做其他的功能做了。 自从用了微信管理工具&#xff0c;提高了运营的工作效率、而且操作非常地简单&#xff0c;还不用…

梯形加减速点动功能块(博途SCL)

梯形速度曲线相关算法介绍,请查看下面博客文章,这里不再赘述,受水平和能力所限文中难免出现错误和不足之处,欢迎大家批评指正,同时感谢大家订阅。 SMART PLC斜坡函数 SMART PLC斜坡函数功能块(梯形图代码)_RXXW_Dor的博客-CSDN博客斜坡函数Ramp的具体应用可以参看下面…

AI人体行为分析:玩手机/打电话/摔倒/攀爬/扭打检测及TSINGSEE场景解决方案

一、AI人体行为分析技术概述及场景 人体姿态分析/行为分析/动作识别AI算法&#xff0c;是一种利用人工智能技术对人体行为进行检测、跟踪和分析的方法。通过计算机视觉、深度学习和模式识别等技术&#xff0c;可以实现对人体姿态、动作和行为的自动化识别与分析。 在场景应用…

小米笔试题——01背包问题变种

这段代码的主要思路是使用动态规划来构建一个二维数组 dp&#xff0c;其中 dp[i][j] 表示前 i 个产品是否可以组合出金额 j。通过遍历产品列表和可能的目标金额&#xff0c;不断更新 dp 数组中的值&#xff0c;最终返回 dp[N][M] 来判断是否可以组合出目标金额 M。如果 dp[N][M…

Opencv-图像噪声(均值滤波、高斯滤波、中值滤波)

图像的噪声 图像的平滑 均值滤波 均值滤波代码实现 import cv2 as cv import numpy as np import matplotlib.pyplot as plt from pylab import mplmpl.rcParams[font.sans-serif] [SimHei]img cv.imread("dog.png")#均值滤波cv.blur(img, (5, 5))将对图像img进行…

Linux内核SPI子系统驱动框架详解

目录 1 spi子系统整体架构图 2 SPI控制器驱动和SPI设备驱动软件架构 3 SPI控制器驱动的整理流程 4 SPI发送数据过程 5 SPI设备驱动 6spidev万能驱动 7 费曼学习法&#xff1a;我录制了一个SPI子系统驱动框架讲解视频 参考文献&#xff1a; 1 spi子系统整体架构图 如上图…

资管巨头贝莱德增持矿企股份,机构资金正在慢慢进入比特币经济……

在比特币减半前夕&#xff0c;比特币挖矿企业股价今年大幅上涨&#xff0c;甚至比BTC上涨幅度还高数倍&#xff0c;非常强势。而据富途最新股权披露数据显示&#xff0c;截至2023年8月31日&#xff0c;已经有3家机构投资者增持了加密挖矿服务商比特小鹿&#xff08;Bitdeer&…

[面试] k8s面试题 2

文章目录 核心组件1.什么是 Kubernetes 中的控制器&#xff08;Controller&#xff09;&#xff1f;请提供一些常见的控制器类型。2.请解释一下 Kubernetes 中的 Ingress 是什么&#xff0c;以及它的作用。3.如何通过命令行在 Kubernetes 中创建一个 Pod&#xff1f;4.Stateful…

Jmeter配置性能监控插件

一、版本不兼容时&#xff0c;有报错 1、当jmeter版本比较高时&#xff0c;只需要从官网安装jmeter-plugins-manager-1.10.jar一个包 2、当jmeter版本较低时&#xff0c;安装JMeterPlugins-Extras-1.4.0.zip、JMeterPlugins-Standard-1.4.0.zip内两个jar包 3、服务器上传文件…

【链表】删除链表的中间节点-力扣2095题

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

Latex Overleaf 写作问题记录

Latex & Overleaf 写作问题记录 公式换行及排列整齐 \begin{equation} \begin{split}Y & a1\\&b2 \end{split} \end{equation}顶格 \noindent求和符号 求和符号&#xff08;上下限上下排列&#xff09; \sum\limlits求和符号&#xff08;上下限右边排列&#…

数据库模块

这里写目录标题 一.数据库设计确定实体之间的关系创建数据表编写实体类二.封装数据库操作封装DButil针对文件的增删查改操作进行一个封装初始化数据库插入文件查询文件删除文件 一.数据库设计 确定实体之间的关系 因为我们要做的是一个文件搜索功能,我们这里的实体,就是文件,…

02-数据结构-线性表

线性表的特点&#xff1a; (1)存在惟一一个被称为"第一个"的数据元素 (2)存在惟一一个被称为"最后一个"的数据元素 (3)除第一个之外&#xff0c;集合中每一个数据元素均只有一个前驱 (4)除最后一个之外&#xff0c;集合中每个数据均只有一个后继 线性表是…

2023华为杯数学建模研赛思路分享——最全版本A题深度解析

问题回顾&#xff1a; WLAN网络信道接入机制建模 1. 背景 无线局域网&#xff08;WLAN, wireless local area network&#xff09;也即Wi-Fi广泛使用&#xff0c;提供低成本、高吞吐和便利的无线通信服务。基本服务集&#xff08;BSS, basic service set&#xff09;是WLAN的…

力扣:106. 从中序与后序遍历序列构造二叉树(Python3)

题目&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可…

深入学习 Redis - 如何使用 Redis 作缓存?缓存更新策略?使用需要注意哪些问题(工作/重点)

目录 一、Redis 作为缓存 1.1、缓存的基本概念 1.1.1、理解 1.1.2、缓存存什么样的数据&#xff1f;二八定律 1.2、如何使用 redis 作为缓存 1.3、缓存更新策略&#xff08;redis 内存淘汰机制 / 重点&#xff09; 1.3.1、定期生成 1.3.2、实时生成 内存淘汰策略&#…

报式套接字通讯实例

报式套接字通讯实例 使用套接字通讯流程 被动端&#xff08;先运行&#xff09; 1、取得SOCKET 2、给SOCKET取得地址 3、收/发消息 4、关闭SOCKET 主动端 1、取得SOCKET 2、给SOCKET取得地址&#xff08;可省略&#xff09; 3、发/收消息 4、关闭SOCKET 各部分代码实现 pr…

exe文件运行后无输出直接闪退如何找解决办法

一.搜索栏搜事件查看器 二.点开windows日志下的应用程序 三.找到错误处 四.搜索异常代码 点开有错误的详细信息&#xff0c;直接用搜索引擎搜索这个异常代码能大致判断是什么问题&#xff0c;给了一个解决思路&#xff0c;不至于不知道到底哪里出了问题

prometheus+node+process-exporter+grafans

安装Prometheus 要在Ubuntu 18.04上安装Prometheus&#xff0c;您可以按照以下步骤进行&#xff1a; sudo apt-get update安装依赖&#xff1a; sudo apt-get install wget tar下载最新的Prometheus版本&#xff1a; wget https://github.com/prometheus/prometheus/releas…

月木学途开发 3.博客模块开发

概述 效果展示 数据库设计 专栏表 DROP TABLE IF EXISTS blog_column; CREATE TABLE blog_column (blogColumnId int(11) NOT NULL AUTO_INCREMENT,blogColumnName varchar(255) DEFAULT NULL,blogColumnCoverImg longtext,blogColumnIntroduction longtext,userId int(11) D…