有一个单链表,提供了头指针和一个结点指针,设计一个函数,在 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)的删除单链表结点的方法的更多相关文章

  1. 删除单链表节点,时间复杂度为O(1)

    一个编程练习,删除单链表一个节点,且时间复杂度控制在O(1)内. 1.核心操作代码如下: struct ListNode { int m_data; ListNode *m_pNext; }; voi ...

  2. 用O(1)的时间复杂度删除单链表中的某个节点

    给定链表的头指针和一个结点指针,在O(1)时间删除该结点.链表结点的定义如下: struct ListNode { int m_nKey; ListNode* m_pNext; }; 函数的声明如下: ...

  3. 数据结构(C语言第2版)----时间复杂度和单链表

    马上要到校招了,复习下相关的基础知识. 时间复杂度是什么? 官方解释: 算法的执行时间需要依据算法所编制的程序在计算机上于运行时所消耗的时间来度量.在算法中可以使用基本的语句的执行次数作为算法的时间复 ...

  4. 单链表的回文判断(O(n)时间复杂度和O(1)的空间复杂度)

    对于单链表来说,判断回文最简单的方法就是遍历链表,将链表中的元素复制到数组中,然后对数组进行判断是否是回文数组,但是这不符合O(1)的空间复杂度. 由于空间复杂度的要求,需要就地操作链表,不能开辟多余 ...

  5. 在O(n) 时间复杂度,O(1)空间复杂度内反转单链表

    在LeetCode中看到判断回文的程序:https://leetcode.com/problems/palindrome-linked-list/ 里面用单链表来存储数据,先反转前半部分的单链表,然后 ...

  6. 感觉单链表是实现BCL ICollection 的最佳方式,所有操作都能以最小的时间复杂度完成

    public interface ICollection<T> : IEnumerable<T>, IEnumerable {     int Count { get; }// ...

  7. C# - 集合类

    C#的集合类命名空间介绍: // 程序集 mscorlib.dll System.dll System.Core.dll // 命名空间 using System.Collections:集合的接口和 ...

  8. 《数据结构》2.3单链表(single linked list)

    //单链表节点的定义 typedef struct node { datatype data; struct node *next; }LNode,*LinkList; //LNode是节点类型,Li ...

  9. C#栈

    线性表.栈和队列这三种数据结构的数据元素以及数据元素间的逻辑关系完全相同,差别是线性表的操作不受限制,而栈和队列的操作受到限制.栈的操作只能在表的一端进行, 队列的插入操作在表的一端进行而其它操作在表 ...

随机推荐

  1. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  2. Logstash实践: 分布式系统的日志监控

    文/赵杰 2015.11.04 1. 前言 服务端日志你有多重视? 我们没有日志 有日志,但基本不去控制需要输出的内容 经常微调日志,只输出我们想看和有用的 经常监控日志,一方面帮助日志微调,一方面及 ...

  3. webpack+react+redux+es6开发模式

    一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...

  4. ASP.NET Core中如影随形的”依赖注入”[上]: 从两个不同的ServiceProvider说起

    我们一致在说 ASP.NET Core广泛地使用到了依赖注入,通过前面两个系列的介绍,相信读者朋友已经体会到了这一点.由于前面两章已经涵盖了依赖注入在管道构建过程中以及管道在处理请求过程的应用,但是内 ...

  5. JavaScript之职责链模式

    一.概述 职责链模式(Chain of responsibility),就是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有 ...

  6. Opserver开源的服务器监控系统(ASP.NET)

    Opserver是Stack Exchange下的一个开源监控系统,系统本身由C#语言开发的ASP.NET(MVC)应用程序,无需任何复杂的应用配置,入门很快.下载地址:https://github. ...

  7. 简记用ArcGIS处理某项目需求中数据的步骤

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1. 背景 项目需求涉及如下几个步骤: a.矢量化 b.获取范围内要素 ...

  8. 基于SignalR的消息推送与二维码描登录实现

    1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于Singl ...

  9. ajax请求和aspx返回数据

    ajax请求: $(function () {            $.ajax({                url: "index.aspx?method=send",  ...

  10. python 数据类型 --- 集合

    1. 注意列表和集合的区别 set 列表表现形式: list_1 = [1,3,4];  集合表现形式:set_1= set() list_1 = [1,2,3,4,23,4,2] print(lis ...