单链表相关操作(插入,删除,查找)

通过上一节我们知道顺序表的优点:

可随机存储(O(1)):查找速度快

存储密度高:每个结点只存放数据元素,而单链表除了存放数据元素之外,还需存储指向下一个节点的指针

http://t.csdn.cn/p7OQf

但是顺序表也有明显的缺点,就是需要大片的连续空间,改变容量不方便,所以出现了单链表

目录

一.初始化单链表

二.插入结点

1.带头结点的插入

2.不带头结点的插入:不存在第’0‘个结点,因此i=1时,需要特殊处理

补充:带头结点

指针结点的后插操作

指针的前插操作

三.删除结点

1.带头节点的删除

2.不带头节点的删除

3.删除指定节点

四.单链表的查找

1.按位查找:查找第i个节点的值

2.按值查找:查找链表中是否有元素e

补充:求表的长度


一.初始化单链表

typedef struct LNode{ElemType data;    //每个节点存放一个数据元素struct LNode *next;//指针指向下一个节点
}LNode,*LinkList;
//这里的LinkList==》typedef struct LNode *LinkList,定义一个指向结构体的指针
//在这里
//LNode *L与LinkList L;//都是表示指向单链表第一个节点的指针
//LNode *L强调的是一个节点
//LinkList L强调的是一个单链表/*不带头节点的单链表
bool InitList(LinkList &L)
{L=NULL;//防止空间中存在脏数据return true;}bool Empty(LinkList L)
{return (L=NULL);
}void test()
{LinkList L;InitList(L);}
*///带头结点的单链表
LinkList InitList(LinkList &L)
{L=(LNode *)malloc(sizeof(LNode));//分配一个头结点if(L==NULL)return NULL;L->next=NULL;//声明一个指向单链表的指针return L;}bool Empty(LinkList L)
{if(L->next==NULL){return true;}    elsereturn false;}
//我们可以把头结点看作第0个结点,这样写代码更加方便

二.插入结点

1.带头结点的插入

bool ListInsert(LinkList &L,int i,ElemType e)//i表示插入的位置,e表示插入的元素
{if(i<1){return false;}LNode *p;//指针p指向当前扫描到的结点int j=0;//当前p指向的是第几个结点p=L;    //指向头节点,头节点是第0个节点while(p!=NULL && j<i-1)//循环找到第i-1个结点{p=p->next;j++;}if(p==NULL){return false;}LNode *s=(LNode *)malloc(sizeof(LNode));s->data=e;s->next=p->next;p->next=s;return true;}

若先p->next=s,再s->next=p->next,即

 带头结点的插入

最好情况:插在表头O(1)

最坏情况:插在表尾O(n)

平均情况:O(n)

2.不带头结点的插入:不存在第’0‘个结点,因此i=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;}LNoden *p;int j=1;//除了这里j=1和带头结点的指针不同,其他是相同的p=L;while(p!=NULL && j<i-1){p=p->next;j++;}if(p==NULL){return false;}LNode *s=(LNode *)malloc(sizeof(LNode));s->data=e;s->next=p->next;p->next=s;return true;
}

删除第一个元素时,需要更改头指针L 

补充:带头结点

指针结点的后插操作

//在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->next=p->next;    p->next=s;return true;}

 指针的前插操作

1.第一种方法:通过前驱节点完成前插操作

需要传入头节点才能找到p的前驱结点,即

bool InsertPriorNode(LinkList L,LNode *p,ElemType e)

bool InsertPriorNode(LinkList L,LNode *p,ElemType e)
{if(p==NULL)return false;LNode *s=(LNode*)malloc(sizeof(LNode));if(s==NULL)return false;LNode *current=L;while(current->next!=p)current=current->next;s->data=e;s->next=current->next;current->next=s;return true;
}

 在这里时间复杂度为O(n),如何减小时间复杂度,可以用第二种方法

2.第二种方法:通过结点的数据交换完成前插操作

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中元素覆盖为ereturn true;}

 关键在于s->data=p->data;p->data=e;这样实现了两节点的数据交换,实现了在p结点前插入e元素,同时这里的时间复杂度是O(1)

所以对于插入节点可以观察到如下两个规律

1.先后再前

s->next=p->next;

p->next=s;

2.先小后大

在第一个节点插入

s->next=L;

L=s        //头指针指向新插入的节点s 

三.删除结点

1.带头节点的删除

bool ListDelete(LinkList &L,int i,ElemType &e)
{if(i<1){return false;}LNode *p=L;int j=0;while(p!=NULL && j<i-1)//这里是寻找要删除结点的前驱结点{p=p->next;j++;}    if(p==NULL)return false;if(p->next==NULL)//如果要删除结点的前驱结点为NULL,那么删除就无意义了return false;LNode *q=p->next;//令q指向被删除结点e=q->data;//用e返回元素的值p->next=q->next;//将*q结点从链表中断开free(q);//释放qreturn true;
}

最好时间复杂度为O(1):删除第一个节点

最坏和平均时间复杂度为O(n)

2.不带头节点的删除

bool ListDelete(LinkList& L, int i, ElemType& e) {if (i < 1)return false;if (i == 1) {    LNode* p = L;L = L->next;free(p);return true;}LNode* p = L;int j = 1;while (p != NULL && j < i - 1) {//寻找删除节点的前驱节点p = p->next;j++;}if (p == NULL || p->next == NULL)return false;LNode* q = p->next;e = q->data;p->next = q->next;free(q);return true;
}

 3.删除指定节点

//删除指定节点p
bool DeleteNode(LNode *p)
{if(p==NULL)return false;LNode *q=p->next;    //    令q指向*p的后继节点q->data=p->next->data;p->next=q->next;//将*q节点从链中断开free(q);//释放后继节点的存储空间return true;}
//如果p的后继节点刚好为NULL,那么p->next->data指向空所以这段代码对此情况不适用
//针对此情况还是要找到其前驱节点,然后进行删除

找前驱节点进行删除

bool DeleteNode(LinkList L, LNode* p, ElemType& e) {if (p == NULL)return false;LNode* q = L;while (q->next != p)q = q->next;q->next = NULL;e = p->data;free(p);return true;
}

四.单链表的查找

1.按位查找:查找第i个节点的值

LNode *GetElem(LinkList L,int i)
{if(i<0)return false;LNode *p=L;int j=0;while(p!=NULL && j<i)//循环找到第i个节点{p=p->next;j++;}return p;}

平均时间复杂度O(n)

2.按值查找:查找链表中是否有元素e

LNode *LocateElem(LinkList L,ElemType e)
{LNode *p=L->next;//从第一个节点开始查找数据域为e的节点while(p!=NULL && p->data!=e)p=p->next;return p;//找到后返回该节点的指针,否则为NULL
}

平均时间复杂度O(n)

补充:求表的长度

int length(LinkList L)
{int len=0;LNode *p=L;while(p!=NULL){p=p->next;len++;}return len;}

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

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

相关文章

【2023年11月第四版教材】《第4章-信息系统管理(合集篇)》

第4章-信息系统管理之管理方法&#xff08;第四版新增章节&#xff09;&#xff08;第一部分&#xff09; 章节说明1 管理方法1.1 信息系统四个要素1.2 信息系统四大领域1.3 信息系统战略三角1.4 信息系统架构转换1.5 信息系统体系架构1.6 信息系统运行1.7 运行和监控1.8 管理和…

北邮邓中亮:深度融合5G+北斗,实现高精准定位

如今&#xff0c;万物互联时代&#xff0c;物与物、物与人、人与人之间需要实现更多的互联。在如此复杂多变的环境中&#xff0c;定位技术面临着着更多挑战和需求&#xff0c;需要不断的创新和改进。唯有如此&#xff0c;才能满足未来智能交通、无人驾驶和工业互联网等领域的高…

kafka基本概念及操作

kafka介绍 Kafka是最初由Linkedin公司开发&#xff0c;是一个分布式、支持分区的&#xff08;partition&#xff09;、多副本的 &#xff08;replica&#xff09;&#xff0c;基于zookeeper协调的分布式消息系统&#xff0c;它的最大的特性就是可以实时的处理大量数据以满足各…

【LeetCode】242 . 有效的字母异位词

242 . 有效的字母异位词&#xff08;简单&#xff09; 方法&#xff1a;哈希表 思路 首先判断两个字符串长度是否相等&#xff0c;不相等直接返回 false&#xff1b;接下来设置一个长度为26 的哈希表&#xff0c;分别对应26个小写字母&#xff1b;遍历两个字符串&#xff0c;…

Go语言工程实践之测试与Gin项目实践

Go 语言并发编程 及 进阶与依赖管理_软工菜鸡的博客-CSDN博客 03 测试 回归测试一般是QA(质量保证)同学手动通过终端回归一些固定的主流程场景 集成测试是对系统功能维度做测试验证,通过服务暴露的某个接口,进行自动化测试 而单元测试开发阶段&#xff0c;开发者对单独的函数…

day-21 代码随想录算法训练营(19)二叉树part07

530.二叉搜索树的最小绝对差 思路一&#xff1a;二叉搜索树的中序遍历必为升序数组&#xff0c;加入数组后计算相邻两个数差值&#xff0c;即可求出最小绝对差 思路二&#xff1a;同样的思路&#xff0c;中序遍历&#xff0c;直接使用指针记录上一个节点&#xff0c;同时更新…

KAFKA第二课之生产者(面试重点)

生产者学习 1.1 生产者消息发送流程 在消息发送的过程中&#xff0c;涉及到了两个线程——main线程和Sender线程。在main线程中创建了一个双端队列RecordAccumulator。main线程将消息发送给RecordAccumulator&#xff0c;Sender线程不断从RecordAccumulator中拉取消息发送到K…

03-基础入门-搭建安全拓展

基础入门-搭建安全拓展 1、涉及的知识点2、常见的问题3、web权限的设置4、演示案例-环境搭建&#xff08;1&#xff09;PHPinfo&#xff08;2&#xff09;wordpress&#xff08;3&#xff09;win7虚拟机上使用iis搭建网站&#xff08;4&#xff09;Windows Server 2003配置WEB站…

C#应用处理传入参数 - 开源研究系列文章

今天介绍关于C#的程序传入参数的处理例子。 程序的传入参数应用比较普遍&#xff0c;特别是一个随操作系统启动的程序&#xff0c;需要设置程序启动的时候不显示主窗体&#xff0c;而是在后台运行&#xff0c;于是就有了传入参数问题&#xff0c;比如传入/h或者/min等等。所以此…

YOLO v8目标跟踪详细解读(二)

上一篇&#xff0c;结合代码&#xff0c;我们详细的介绍了YOLOV8目标跟踪的Pipeline。大家应该对跟踪的流程有了大致的了解&#xff0c;下面我们将对跟踪中出现的卡尔曼滤波进行解读。 1.卡尔曼滤波器介绍 卡尔曼滤波&#xff08;kalman Filtering&#xff09;是一种利用线性…

欧拉OS 使用 CentOS 7 yum repo

一、下载CentOS的repo的yum文件 任何基于CentOS的yum的repo 的url是这样的&#xff1a; 但欧拉OS输出这个变量为&#xff1a;openEuler 20.03 (LTS-SP3) 那明显欧拉想要使用这个yum的url找不到这个版本&#xff0c; 所以直接讲这个变量替换为 7, Centos 7的7 然后执行&…

wget 详解

wget 详解 wget 详解基本用法&#xff1a;命令参数&#xff1a;递归下载&#xff1a;断点续传&#xff1a;限速下载&#xff1a;后台下载&#xff1a; 示例 wget 详解 wget&#xff08;Web Get&#xff09;是一个用于从网络上下载文件的命令行工具&#xff0c;常用于在 Linux …

从零实战SLAM-第七课(多视角几何)

在七月算法报的班&#xff0c;老师讲的蛮好。好记性不如烂笔头&#xff0c;关键内容还是记录一下吧&#xff0c;课程入口&#xff0c;感兴趣的同学可以学习一下。 --------------------------------------------------------------------------------------------------------…

整型int溢出引起的crash

线上系统发生了crash&#xff0c;后发现是整型溢出。 1、初始化函数的伪代码&#xff1a; init_mem(int count, int size){for(int i0; i<count; i)mem_list[i] i*size; # 溢出发生的地方} 2、问题分析&#xff1a; 原有的变量 i、size 为有符号的int类型&#xff0c;i…

设计模式--策略模式

目录 一.场景 1.1场景 2.2 何时使用 2.3个人理解 二. 业务场景练习 2.1业务: 2.2具体实现 2.3思路 三.总结 3.1策略模式的特点&#xff1a; 3.2策略模式优点 3.3策略模式缺点 一.场景 1.1场景 许多相关的类仅仅是行为有异&#xff0c;也就是说业务代码需要根据场景不…

Android数字价格变化的动画效果的简单实现

原理&#xff1a;使用ValueAnimator属性动画类实现&#xff0c;它通过值的改变手动设置对象的属性值来实现动画效果。直接贴代码&#xff1a; public static void doNumberAnim(TextView tvPrice, float startNumber, float endNumber) {ValueAnimator animator ValueAnimato…

C语言中的 RSA加密和解密算法: 深度探索与实现

C语言中的 RSA加密和解密算法: 深度探索与实现 RSA加密算法是一种非对称加密算法&#xff0c;即公开密钥加密&#xff0c;私有密钥解密。在公开密钥加密和私有密钥解密的过程中&#xff0c;密钥是不同的&#xff0c;这是与其他加密算法的主要区别。RSA算法的安全性依赖于大数分…

ssm+mybatis无法给带有下划线属性赋值问题

原因&#xff1a;mybaitis根据配置&#xff0c;将有下划线的字段名改为了驼峰格式。 具体见&#xff1a;ssmmybatis无法给带有下划线属性赋值问题&#xff0c;无法获取数据库带下划线的字段值 - 开发者博客 解决方式&#xff1a; 直接将实体类中的下划线去掉返回值使用resul…

归并排序 与 计数排序

目录 1.归并排序 1.1 递归实现归并排序&#xff1a; 1.2 非递归实现归并排序 1.3 归并排序的特性总结: 1.4 外部排序 2.计数排序 2.1 操作步骤: 2.2 计数排序的特性总结: 3. 7种常见比较排序比较 1.归并排序 基本思想: 归并排序(MERGE-SORT)是建立在归并操作上的一种…

代理技术在网络安全、爬虫和数据隐私中的多重应用

1. Socks5代理&#xff1a;灵活的数据中转 Socks5代理协议在网络通信中起着关键作用。与其他代理技术不同&#xff0c;Socks5代理不仅支持TCP连接&#xff0c;还能够处理UDP流量&#xff0c;使其在需要实时数据传输的场景中表现尤为出色。通过将请求和响应中转到代理服务器&am…