【数据结构】二、线性表:2.单链表的插入、删除、查找

news2024/12/22 23:09:27

文章目录

        • 2.3插入
          • 2.3.1按位序插入
          • 2.3.2指定结点后插入
          • 2.3.3指定结点前插入
        • 2.4删除
          • 2.4.1按位序删除
          • 2.4.2指定结点删除
        • 2.5查找
          • 2.5.1按位查找
          • 2.5.2按值查找

2.3插入
2.3.1按位序插入

ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。

  1. 带头结点

把头结点看作第0个结点,位置 i 就是 i-1 个结点

//在第i个位置插插入元素e(带头结点)
bool ListInsert(LinkList &L, int i, ElemType e){
    if(i<1)		//位序1是头结点
        return false;
    LNode *p;	//指针p指向当前扫描到的结点
    int j=0;	//当前p指向的是第几个结点
    p = L;		//L指向头结点,头结点是第0个结点(不存数据)
    
    //循环找到第 i-1 个結点,p是前一个结点,插入p的后面
    while (p!=NULL && j<i-1) {
        p=p->next;
        j++;
    }
    
    if(p==NULL)		//i值不合法
        return false;
    
    LNode *s = (LNode *)malloc(sizeof(LNode));//新结点
    s->data = e;
    s->next = p->next;
    p->next = s;	//将结点s连到p之后
    return true;	//插入成功
}

请添加图片描述
有一个while所以时间复杂度是O(n)

  1. 不带头结点
bool ListInsert(LinkList &L, int i, ElemType e){ 
    if(i<1)
        return false;
    if(i==1){ 	//插入第1个结点的操作与其他结点操作不同
        LNode *s = (LNode *) malloc(sizeof(LNode));
        s->data = e;
        s->next = L;
        L=s;	//头指针指向新结点
        return true;
    }
    LNode *p;	//指针p指向当前扫描到的结点
    int j=1;	//当前p指向的是第几个结点
    p=L;		//p指向第1个结点(注意:不是头结点)
    
    //循环找到第 i-1 个結点,p是前一个结点,插入p的后面
    while (p!=NULL && j<i-1) { 
        p=p->next;
        j++;
    }
    
    if(p==NULL)	//i值不合法
        return false;
    LNode *s = (LNode *) malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;//插入成功
}
2.3.2指定结点后插入

InsertNextNode(LNode *p, ElemType e)

//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p, ElemType e){
    if (p==NULL)
        return false;
    LNode *s = (LNode *)malloc(sizeof(LNode));
    if (s==NULL)	//内存分配失败
        return false;
    s->data = e;		//用结点s保存数据元素e
    s->next = p->next;
    p->next = s;		//将结点s连到p之后
    return true;
}

时间复杂度O(1)

2.3.3指定结点前插入

InsertPriorNode(LNode *p, ElemType e)

//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p, ElemType e){
    if (p==NULL)
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	if (s==NULL)	//内存分配失败
		return false;
    //
	s->next = p->next;
	p->next = s;	//新结点s连到p之后
	s->data = p->data;	//将p中元素复制到s中
	p->data = e;	//p中元素覆盖为e
    return true;
}

转移p结点的内容到后面,在逻辑上实现在p结点前插入。

原链表
删除
p,现在内容是新的e
...etc
p-next
...
新结点s,内容是之前p结点的内容

时间复杂度O(1)

前插操作:在p结点之前插入结点 s(王道书版本)

//前插操作:在p结点之前插入结点s
bool InsertPriorNode(LNode *p, LNode *s){
    if (p==NULL || s==NULL)
        return false;
    s->next = p->next;
    p->next = s;	//s连到p之后
    //交换数据域部分
    ElemType temp = p->data;
    p->data = s->data;
    s->data = temp;
    return true;
}
2.4删除
2.4.1按位序删除

ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。

//按位序删除(带头结点)
bool ListDelete(LinkList &L,int i,ElemType e){
    if(i<1)B
    	return false;
    LNode *p;	//指针p指向当前扫描到的结点
    int j = 0;	//当前p指向的是第几个结点
    p = L;		//L指向头结点,头结点是第0个结点(不存数据)
    //循环找到第 i-1 个结点
    while(p!=NULL && j<i-1){
        p=p->next;
        j++;
    }
    
    if(p==NULL)	//i值不合法
        return false;
    LNode *q = p->next;	//令q指向被删除结点(拿到结点),也就是p->next
    e = q->data;		//用e返回元素的值
    p->next = q->next;	//将*q结点从链中“断开”
    free(q);			//释放结点的存储空间
    return true;		//删除成功
}

例图:

原链表
等价
传递给
删除
删除
p
...etc
p-next,q
...
新结点q,释放空间
返回值e

时间复杂度:O(n)

2.4.2指定结点删除

DeleteNode(LNode * p)

//删除指定结点p
bool DeleteNode(LNode * p)
{
	if (p == NULL)		//若删除的节点为空结点,操作无效
		return false;
	LNode *q = p->next;	//定义一个q指针,令q指向*p的后继结点
	p->data = p->next->data;//和后继结点交换数据域,相当于将p节点的后一个结点的数据赋值到p结点中
	p->next = q->next;    	//将*q结点从链中“断开” 
	free(q);            	//释放后继结点的存储空间
	return true;
}

时间复杂度:O(1)

由于需删除结点的前驱结点未知,或者要删除的是第一个结点,且不带头结点。那么换个思路,创建一个q指针指向p结点的后继结点,将p结点的后继结点q中的数据覆盖到p结点数据域中,然后令p结点指向q结点的后继结点: p->next = q->next;再删掉“悬空”的q结点完成操作。

等同于:1->2->3->4,若要删掉1,可以先令前两个数据交换,2->1->3->4,再让1的指针链断开,令2指向3: 2->(1)-3->4, 把1断开,于是就是2->3->4。

注意:如果要删除的p结点是最后一个结点,以上偷天换日法无法使用,我们只能从表头开始依次往后寻找p的前驱,时间复杂度为O(n)。

2.5查找
2.5.1按位查找

GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值。

单链表按位查找是指根据节点在链表中的位置(即节点序号或下标)来查找节点的操作。通常情况下,我们需要查找的节点序号是从1开始计数的,即第1个节点、第2个节点、第3个节点等。基本思路是从链表头节点开始,遍历链表,直到找到第k个节点,或者链表遍历结束。如果链表遍历结束仍未找到第k个节点,则返回空指针。

//按位查找
LNode* GetElem(LinkList L, int i)
{
	if(i < 0)		//判断i是否合法
		return NULL;
	LNode *p;		//指针p指向当前扫描到的结点
	int j=0;		//当前p指向的是第几个结点
	p=L;			//L指向头结点,头结点是第0个结点(不存数据)
	while(p!=NULL && j<i){	//寻找第i个结点
		p=p->next;	//让p指针依次往后移
		j++;
	}
	return p;
}

王道书版:

LNode* GetElem(LinkList L, int i){
    int j=1;
    LNode *p=L->next;
    
    if(i==0)	//特殊情况是头结点
        return L;
    if(i<1)		//小于1的结点不合法
        return NULL;
    
    while(p!=NULL && j<i){
        p=p->next;
        j++;
    }
    return p;
}

时间复杂度:O(n)

请添加图片描述

2.5.2按值查找

LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素。

  • 单链表查找需要遍历整个链表,时间复杂度为 O(n),其中 n 是链表节点的个数。
  • 当链表为空时,需要特别处理。
  • 如果目标值在链表中不存在,可能需要额外处理,比如返回一个空指针,或者打印出 “Not Found” 等提示信息。
  • 需要根据具体问题和代码实现,特别注意链表头节点指针的正确性,以及节点指针的移动和连接等操作。
//按值查找, 找到数据域 ==e 的结点
LNode* LocateElem(LinkList L, ElemType e) {
	LNode *p = L->next;
	//从第1个结点开始查找数据域为e的结点
	while(p != NULL && p->data != e)
		p = p->next;
	return p;    //找到后返回该结点指针,否则返回NULL
}

时间复杂度为:O(n)

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

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

相关文章

【MATLAB第98期】基于MATLAB的MonteCarlo蒙特卡罗结合kriging克里金代理模型的全局敏感性分析模型【更新中】

【MATLAB第98期】基于MATLAB的Monte Carlo蒙特卡罗结合kriging克里金代理模型的全局敏感性分析模型【更新中】 PS:因内容涉及较多&#xff0c;所以一时半会更新不完 后期会将相关原理&#xff0c;以及多种功能详细介绍。 麻烦点赞收藏&#xff0c;及时获取更新消息。 引言 在…

从《繁花》看图数据库的关联力!

2024年开年&#xff0c;最热的电视剧非《繁花》莫属。 这部现象级剧集不仅在全国掀起了一股怀旧潮&#xff0c;还引发了对故事情节和人物关系的深入探讨。 随着《繁花》的热播&#xff0c;不少观众为了更好地理解复杂的故事情节&#xff0c;开始自制人物关系图。 这些关系图以…

【Spring Boot 3】获取已注入的Bean

【Spring Boot 3】获取已注入的Bean 背景介绍开发环境开发步骤及源码工程目录结构总结 背景 软件开发是一门实践性科学&#xff0c;对大多数人来说&#xff0c;学习一种新技术不是一开始就去深究其原理&#xff0c;而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历…

java SSM科研管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM科研管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S…

OPC UA 学习笔记:状态机/有限状态机

有限状态机 有限状态机 &#xff08;FSM&#xff09; 是程序员、数学家、工程师和其他专业人士用来描述具有有限数量条件状态的系统的数学模型。 有限状态机的构成包括以下内容&#xff1a; 一组潜在的输入事件。与潜在输入事件相对应的一组可能的输出事件。系统可以显示的一…

19.题目:编号3865 Alice与Bob的爱恨情仇

题目&#xff1a; ###该题主要考察思维、和博弈 &#xff08;写起来容易&#xff0c;但是不太好想&#xff09; #include<bits/stdc.h> using namespace std; int main(){int n,k;cin>>n>>k;int ans0,x;while(n--){cin>>x;ansx%2;}if(ans%2){cout<…

Effective C++ 学习笔记 条款16 成对使用new和delete时要采取相同形式

以下动作有什么错&#xff1f; std::string *stringArray new std::string[100]; // ... delete stringArray;每件事看起来都井然有序&#xff0c;使用了new&#xff0c;也搭配了对应的delete。但还是有某样东西完全错误&#xff1a;你的程序行为未定义。至少&#xff0c;str…

进程:守护进程

一、守护进程的概念 守护进程是脱离于终端控制&#xff0c;且运行在后端的进程。&#xff08;孤儿进程&#xff09;守护进程不会将信息显示在任何终端上影响前端的操作&#xff0c;也不会被终端产生的任何信息打断&#xff0c;例如&#xff08;ctrlc&#xff09;.守护进程独立…

[密码学]入门篇——加密方式

一、概述 加密方法主要分为两大类&#xff1a; 单钥加密&#xff08;private key cryptography&#xff09;&#xff1a;加密和解密过程都用同一套密码双钥加密&#xff08;public key cryptography&#xff09;&#xff1a;加密和解密过程用的是两套密码 历史上&#xff0c…

POS 之 最终确定性

Gasper Casper 是一种能将特定区块更新为 最终确定 状态的机制&#xff0c;使网络的新加入者确信他们正在同步规范链。当区块链出现多个分叉时&#xff0c;分叉选择算法使用累计投票来确保节点可以轻松选择正确的分叉。 最终确定性 最终确定性是某些区块的属性&#xff0c;意味…

离散数学例题——5.图论基础

基本的图 关联矩阵 子图和补图 度数和握手定理 注意&#xff01;&#xff01;&#xff01;无向图的度数&#xff0c;要行/列和对角线值 根据度数序列判定是否为无向图 度和握手定理证明题 竞赛图 同构图 自补图 通路和回路数量 通路和回路数量 最短路径——dijkstra算法 连通…

21、状态模式(行为性模式)

版本一、get状态指针 #include <iostream> using namespace std;//前置声明 class Context;//状态 class State{ public://4个状态virtual void toUp (Context& context){ }virtual void toDown (Context& context){ }virtual void toLeft (Context& cont…

打造一款用于照片局部修复的“在线橡皮擦”应用(基于Django5和Pytorch,含完整代码)

目录 一、任务概述二、Django微服务开发2.1 创建项目2.1.1 创建Django项目2.1.2 创建主页面2.1.3 编写视图处理函数2.1.4 配置访问路由url2.1.5 启动项目 2.2 前端开发2.2.1 集成Bootstrap52.2.2 初始化各组件2.2.3 自适应展示图像2.2.4 橡皮擦涂抹2.2.5 使用Ajax传输图像 2.3 …

本地部署推理TextDiffuser-2:释放语言模型用于文本渲染的力量

系列文章目录 文章目录 系列文章目录一、模型下载和环境配置二、模型训练&#xff08;一&#xff09;训练布局规划器&#xff08;二&#xff09;训练扩散模型 三、模型推理&#xff08;一&#xff09;准备训练好的模型checkpoint&#xff08;二&#xff09;全参数推理&#xff…

简站wordpress主题看上去差不多 实际大不一样

有人说简站wordpress主题&#xff0c;都差不多嘛。我表示无语。表面看上去是差不多的&#xff0c;实际的细节是不一样的。 下面以编号&#xff1a;JZP4431和编号&#xff1a;JZP4878这两个主题为例子来讲一下&#xff0c;简站wordpress主题&#xff0c;在细节方面的不一样之处…

最简单的基于 FFmpeg 的内存读写的例子:内存视频播放器

最简单的基于 FFmpeg 的内存读写的例子&#xff1a;内存视频播放器 最简单的基于 FFmpeg 的内存读写的例子&#xff1a;内存视频播放器正文源程序结果工程文件下载参考链接 最简单的基于 FFmpeg 的内存读写的例子&#xff1a;内存视频播放器 参考雷霄骅博士的文章&#xff0c;…

Mysql深入学习 基础篇 Ss.05多表查询语法及案例

世界总是在推着我走&#xff0c;我自己一个人也能站稳 —— 24.3.7 一、多表关系 1.概述 项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个…

Mr. Young‘s Picture Permutations

Mr. Young’s Picture Permutations 看了李煜东老师的答案。 对dp的转移有了一点别的理解。 之前都是按y总那样考虑当前状态是由那些状态转移过来的。 这道题目看算阶上的思考方式&#xff0c;考虑的是当前状态能够转移到那些状态。 更具体点就是说&#xff0c;考虑 f [ i ] […

千帆AppBuilder使用指南-组件中心

应用中心 百度智能云千帆AppBuilder&#xff08;以下简称为AppBuilder&#xff09;应用中心&#xff0c;提供了大量可以立即体验的应用示例&#xff0c;开发者可以在这里搜索感兴趣的应用进行使用。 官方应用&#xff1a;AppBuilder官方提供的应用&#xff0c;可以立即体验应用…

input输入框的23中类型

HTML 的 <input> 元素支持多种类型&#xff0c;这些类型决定了用户如何与表单控件进行交互。以下是 HTML5 中 <input> 元素的 23 种类型&#xff0c;以及每种类型的代码示例和效果图的描述&#xff08;请注意&#xff0c;由于文本的限制&#xff0c;我无法直接在这…