时间复杂度分别为 O(n)和 O(1)的删除单链表结点的方法
有一个单链表,提供了头指针和一个结点指针,设计一个函数,在 O(1)时间内删除该结点指针指向的结点。
众所周知,链表无法随机存储,只能从头到尾去遍历整个链表,遇到目标节点之后删除之,这是最常规的思路和做法。

如图所示,删除结点 i,那么只需找到 i 的前驱 h,然后连 h 到 j,再销毁i 即可。虽然可以安全的删除 i 结点,但是是顺序查找找到 i,之后删除,时间复杂度是 O(n)级别的。具体做法就是:顺序查找整个单链表,找到要删除结点 i 的直接前驱 h,把 h额 next 指向i 的 next ,再删除 i 结点即可
现在假设的是我们知道这个单链表里一定存在我们需要删除的结点(也就是存在目标结点),因为是单链表,结点没有前驱,那么找到前驱,我们只能从头结点开始扫描整个链表,那么,我们可不可以去找到要删除结点的下一个结点呢?
时间复杂度为 O(1)的删除单链表结点的方法
如果我们直接找到要删除结点的下一个结点,是非常方便的,不用去遍历整个链表,只需把删除结点 i 的下一个结点j 的内容复制到 i 上,然后把 i 的指针指向 j 的next,然后再删除j 结点。等价于删除了 i 结点。整个过程无需遍历整个链表,时间复杂度是 O(1)级别
继续思考这个思路:这个方法,依靠的是结点的后继指针,如果要删除的结点在末尾,也就说,结点没有后继,怎么处理?
本题目没有给出尾指针,那么此种特殊情况,还是需要从头到尾遍历整个链表,得到该结点的前驱,然后删除该结点。
继续思考,如果单链表只有一个结点,那么删除该结点需要做什么处理?
如果单链表只有一个结点,现在需要删除这个结点,也就是链表的头结点(尾结点),那么在删除之后,需要把头指针指向 NULL处理。
代码实现如下:
typedef struct Node{
int data;
Node *next;
} Node, *List;
void deleteNode(List *head, Node *del)
{
Node *p = NULL;
//判断链表是否为空
if (!head) {
cout << "链表为空!" << endl;
exit();
}
//如果删除的结点是尾结点
if (del->next == NULL) {
p = *head;
//仍然需要遍历链表
while (p->next != del) {
//顺次后移
p = p->next;
}
//找到前驱,断链
p->next = NULL;
//删除结点
delete del;
//预防野指针
del = NULL;
}
//如果单链表只有一个结点
else if(*head == del){
//无需断链,直接删除
delete del;
del = NULL;
//头指针处理
*head = NULL;
}
//如果链表里有多个结点,且删除的结点不是尾结点
else{
//无须遍历链表
p = del->next;
del->data = p->data;
del->next = p->next;
delete p;
p = NULL;
}
}
时间复杂度分析:
如果是删除非末位的结点,且结点有n(n>1)个,那么时间复杂度是 o(1),对于尾结点,是 o(n),总得来说,是【(n-1)o(1)+o(n)】/ n,结果还是 o(1),复合要求。
注意
1、考虑问题要全面,不要丢三落四,以为出了结果,就算完成任务了。需要严谨的求学问。
2、这个题目的思路其实是建立在客户事先知道本链表里存在需要删除的结点。如果不知道,我们还是需要先遍历整个链表进行查找!那样时间复杂度还是 o(n)。
3、关于删除结点,往往都是只能想到找到前驱,删除,但是逆向思路看,不一定说,删除结点,就一定要删除这个结点,我们可以找到结点的后继,然后通过内容复制,删除该结点的后继结点,来达到删除该结点一样的效果。
欢迎关注
dashuai的博客是终身学习践行者,大厂程序员,且专注于工作经验、学习笔记的分享和日常吐槽,包括但不限于互联网行业,附带分享一些PDF电子书,资料,帮忙内推,欢迎拍砖!

时间复杂度分别为 O(n)和 O(1)的删除单链表结点的方法的更多相关文章
- 删除单链表节点,时间复杂度为O(1)
一个编程练习,删除单链表一个节点,且时间复杂度控制在O(1)内. 1.核心操作代码如下: struct ListNode { int m_data; ListNode *m_pNext; }; voi ...
- 用O(1)的时间复杂度删除单链表中的某个节点
给定链表的头指针和一个结点指针,在O(1)时间删除该结点.链表结点的定义如下: struct ListNode { int m_nKey; ListNode* m_pNext; }; 函数的声明如下: ...
- 数据结构(C语言第2版)----时间复杂度和单链表
马上要到校招了,复习下相关的基础知识. 时间复杂度是什么? 官方解释: 算法的执行时间需要依据算法所编制的程序在计算机上于运行时所消耗的时间来度量.在算法中可以使用基本的语句的执行次数作为算法的时间复 ...
- 单链表的回文判断(O(n)时间复杂度和O(1)的空间复杂度)
对于单链表来说,判断回文最简单的方法就是遍历链表,将链表中的元素复制到数组中,然后对数组进行判断是否是回文数组,但是这不符合O(1)的空间复杂度. 由于空间复杂度的要求,需要就地操作链表,不能开辟多余 ...
- 在O(n) 时间复杂度,O(1)空间复杂度内反转单链表
在LeetCode中看到判断回文的程序:https://leetcode.com/problems/palindrome-linked-list/ 里面用单链表来存储数据,先反转前半部分的单链表,然后 ...
- 感觉单链表是实现BCL ICollection 的最佳方式,所有操作都能以最小的时间复杂度完成
public interface ICollection<T> : IEnumerable<T>, IEnumerable { int Count { get; }// ...
- C# - 集合类
C#的集合类命名空间介绍: // 程序集 mscorlib.dll System.dll System.Core.dll // 命名空间 using System.Collections:集合的接口和 ...
- 《数据结构》2.3单链表(single linked list)
//单链表节点的定义 typedef struct node { datatype data; struct node *next; }LNode,*LinkList; //LNode是节点类型,Li ...
- C#栈
线性表.栈和队列这三种数据结构的数据元素以及数据元素间的逻辑关系完全相同,差别是线性表的操作不受限制,而栈和队列的操作受到限制.栈的操作只能在表的一端进行, 队列的插入操作在表的一端进行而其它操作在表 ...
随机推荐
- SQLSERVER走起 APP隆重推出
SQLSERVER走起 APP隆重推出 为方便大家查看本微信公众以前推送的文章,QQ群里面的某位SQLSERVER重度爱好者开发了<SQLSERVER走起>的APP 以供大家一起交流 网页 ...
- 用C语言封装OC对象(耐心阅读,非常重要)
用C语言封装OC对象(耐心阅读,非常重要) 本文的主要内容来自这里 前言 做iOS开发的朋友,对OC肯定非常了解,那么大家有没有想过OC中NSInteger,NSObject,NSString这些对象 ...
- continue break 区别
在循环中有两种循环方式 continue , break continue 只是跳出本次循环, 不在继续往下走, 还是开始下一次循环 break 将会跳出整个循环, 此循环将会被终止 count = ...
- springmvc的拦截器
什么是拦截器 java里的拦截器是动态拦截action调用的对象.它提供了一种机制可以使 ...
- [转载]一个标准java程序员的进阶过程
第一阶段:Java程序员 技术名称 内 容 说明 Java语法基础 基本语法.数组.类.继承.多态.抽象类.接口.object对象.常用类(Math\Arrarys\S ...
- jQuery标准的AJAX模板
$('#saveInformationTemplate_button').on('click', function(){ if(isEmpty($("#name").val())) ...
- postgresql 基本语法
postgresql数据库创建/修改/删除等写入类代码语法总结: 1,创建库 2,创建/删除表 2.1 创建表 create table myTableName 2.2 如果表不存在则创建表 crea ...
- ABP源码分析二:ABP中配置的注册和初始化
一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...
- SSD框架训练自己的数据集
SSD demo中详细介绍了如何在VOC数据集上使用SSD进行物体检测的训练和验证.本文介绍如何使用SSD实现对自己数据集的训练和验证过程,内容包括: 1 数据集的标注2 数据集的转换3 使用SSD如 ...
- 机器指令翻译成 JavaScript —— No.2 跳转处理
上一篇,我们发现大多数 6502 指令都可以直接 1:1 翻译成 JS 代码,但除了「跳转指令」. 跳转指令,分无条件跳转.条件跳转.从另一个角度,也可分: 静态跳转:目标地址已知 动态跳转:目标地址 ...