题目

给定单链表头指针和一个结点指针,定义一个函数在O(1)时间内删除该结点。

分析

对于上图实例链表(a)删除指针p有两种方式

  • 思路1:(b)找到前一个指针pre,赋值pre->next = p->next,删掉p
  • 思路2:(c)目的是删除p,但是不删p,直接用p->next的值赋值给p,把p->next删除掉(好处:不用遍历找到p的前一个指针pre,O(1)时间内搞定)

于是,定位到思路2,但是思路2有两个特例:

  1. 删除的是尾指针,需要遍历找到前一个指针
  2. 整个链表就一个结点(属于删尾指针,但没法找到前面的指针,需要开小灶单独处理)

大体算法思路

待删指针不是尾指针:
待删指针的值用待删指针的下一个指针的值覆盖
删掉待删指针的下一个指针
待删指针是尾指针:
待删指针同时是头指针:
删掉头指针
待删指针不是头指针
找到待删指针的前一个指针
删掉待删指针,前一个指针的next赋值为空

参考代码

bool deleteNode(ListNode *&head, ListNode *p)
{
if(!p || !head)
return false;
if(p->m_pNext != NULL) //不是尾指针
{
ListNode *del = p->m_pNext;
p->m_nValue = del->m_nValue;
p->m_pNext = del->m_pNext;
delete del;
del = NULL;
}
else if(head == p) //是尾指针,同时只有一个结点
{
delete p;
head = NULL;
}
else //是尾指针,同时有多个结点
{
ListNode *tmp = NULL, *pre = head;
while(pre->m_pNext != p)
{
pre = pre->m_pNext;
}
delete p;
p = NULL;
pre->m_pNext = NULL;
}
return true;
}

完整代码1

#include <iostream>
using namespace std; struct ListNode
{
int m_nValue;
ListNode* m_pNext;
}; bool deleteNode(ListNode *&head, ListNode *p)
{
if(!p || !head)
return false;
if(p->m_pNext != NULL)
{
ListNode *del = p->m_pNext;
p->m_nValue = del->m_nValue;
p->m_pNext = del->m_pNext;
delete del;
del = NULL;
}
else if(head == p)
{
delete p;
head = NULL;
}
else
{
ListNode *tmp = NULL, *pre = head;
while(pre->m_pNext != p)
{
pre = pre->m_pNext;
}
delete p;
p = NULL;
pre->m_pNext = NULL;
}
return true;
}
void createList(ListNode *&head)
{
head = new(ListNode);
head->m_nValue = ;
head->m_pNext = NULL; ListNode *p2 = new(ListNode);
p2->m_nValue = ;
p2->m_pNext = NULL;
head->m_pNext = p2; ListNode *p3 = new(ListNode);
p3->m_nValue = ;
p3->m_pNext = NULL;
p2->m_pNext = p3; ListNode *p4 = new(ListNode);
p4->m_nValue = ;
p4->m_pNext = NULL;
p3->m_pNext = p4;
} void deleteList(ListNode *p)
{
ListNode *next = NULL;
while(p != NULL)
{
cout << p->m_nValue << endl;
next = p->m_pNext;
delete p;
p = NULL;
p = next;
}
} int main()
{
ListNode *head = NULL;
createList(head);
ListNode *p = head->m_pNext->m_pNext->m_pNext;
deleteNode(head, p);
deleteList(head);
}

完整代码2

#include <iostream>
using namespace std; struct ListNode
{
int m_nValue;
ListNode* m_pNext;
}; bool deleteNode(ListNode **head, ListNode *p)
{
if(!p || !head)
return false;
if(p->m_pNext != NULL)
{
ListNode *del = p->m_pNext;
p->m_nValue = del->m_nValue;
p->m_pNext = del->m_pNext;
delete del;
del = NULL;
}
else if(*head == p)
{
delete p;
*head = NULL;
}
else
{
ListNode *tmp = NULL, *pre = *head;
while(pre->m_pNext != p)
{
pre = pre->m_pNext;
}
delete p;
p = NULL;
pre->m_pNext = NULL;
}
return true;
}
void createList(ListNode *&head)
{
head = new(ListNode);
head->m_nValue = ;
head->m_pNext = NULL; ListNode *p2 = new(ListNode);
p2->m_nValue = ;
p2->m_pNext = NULL;
head->m_pNext = p2; ListNode *p3 = new(ListNode);
p3->m_nValue = ;
p3->m_pNext = NULL;
p2->m_pNext = p3; ListNode *p4 = new(ListNode);
p4->m_nValue = ;
p4->m_pNext = NULL;
p3->m_pNext = p4;
} void deleteList(ListNode *p)
{
ListNode *next = NULL;
while(p != NULL)
{
cout << p->m_nValue << endl;
next = p->m_pNext;
delete p;
p = NULL;
p = next;
}
} int main()
{
ListNode *head = NULL;
createList(head);
ListNode *p = head->m_pNext->m_pNext;
deleteNode(&head, p);
deleteList(head);
}

分析

删除非尾结点时间复杂读为O(1),删除尾结点的时间复杂读为O(n), 平均时间复杂度为[(n-1)*O(1) + O(N)] / N = O(1)

还有删除函数并不能处理待删结点就是该链表中的指针,因此需要人为调用时控制,如果得验证的话,那就没必要做这些处理了,直接O(N)

技术细节——传值操作

#include <iostream>
using namespace std; struct ListNode
{
int m_nValue;
ListNode* m_pNext;
}; void createList(ListNode *head)
{
head = new(ListNode);
head->m_nValue = ;
head->m_pNext = NULL;
}
void deleteList(ListNode *p)
{
ListNode *next = NULL;
while(p != NULL)
{
cout << p->m_nValue << endl;
next = p->m_pNext;
delete p;
p = NULL;
p = next;
}
} int main()
{
ListNode *head = NULL;
createList(head);
cout << head << endl;
deleteList(head);
}

主函数中的指针head为传值调用,传到函数并没有改变主函数中的值,图示

改进的措施就是引用传值,直接操纵原指针。

O(1)时间内删除指定链表结点的更多相关文章

  1. 在O(1)时间内删除单链表结点

    // 在O(1)时间内删除单链表结点 /* 思考: 很显然链表是一个节点地址不连续的存储结构 删除节点一般很容易会想到是修改p节点的前一个节点的next为p->next 然而除非是双向链表,否则 ...

  2. 在O(1)时间删除指定链表结点

    #region 在O(1)时间删除指定链表结点 /// <summary> /// 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. /// </summa ...

  3. 在O(1)时间内删除单链表结点

    给定单链表的一个结点的指针,同时该结点不是尾结点,此外没有指向其它任何结点的指针,请在O(1)时间内删除该结点. int deleteNode(LNode **head, LNode **node) ...

  4. 时间复杂度分别为 O(n)和 O(1)的删除单链表结点的方法

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

  5. 13:在O(1)时间内删除单向链表中的一个节点

    思路:如果从首部开始依次查找,那么时间是O(n). 既然我们知道要删除的结点i,那么我们就知道它指向的下一个结点j,那么我们可以将j的内容复制到i,然后将i的指针指向j的下一个结点,这样虽然看起来我们 ...

  6. 《剑指offer》面试题13—O(1)时间删除链表结点

    题目:给定单向链表的头指针和某结点指针,实现函数在O(1)时间内删除指定节点. 思路:由于没有要删除结点(j结点)的前一个结点(i结点)指针,通常想法是从头开始遍历找到指定结点的前一个结点(i结点), ...

  7. pta 奇数值结点链表&&单链表结点删除

    本题要求实现两个函数,分别将读入的数据存储为单链表.将链表中奇数值的结点重新组成一个新的链表.链表结点定义如下: struct ListNode { int data; ListNode *next; ...

  8. 【编程题目】在 O(1)时间内删除链表结点

    60.在 O(1)时间内删除链表结点(链表.算法).题目:给定链表的头指针和一个结点指针,在 O(1)时间删除该结点.链表结点的定义如下:struct ListNode{int m_nKey;List ...

  9. (剑指Offer)面试题13:在O(1)时间内删除链表结点

    题目: 在给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间内删除该结点.链表结点与函数的定义如下: struct ListNode{ int val; ListNode* next; } ...

随机推荐

  1. C#外挂QQ找茬辅助源码,早期开发

    这是一款几年前开发的工具,当年作为一民IT纯屌,为了当年自己心目中的一位女神熬夜开发完成.女神使用后找茬等级瞬间从眼明手快升级为三只眼...每次看到这个就会想起那段屌丝与女神的回忆.今天特地把代码更新 ...

  2. MySQL 主从数据库设置

    1.复制的介绍 MySQL 支持单向.异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器.主服务器将更新写入二进制日志文件,并维护文件的一个索引 以跟踪日志循环.这些日志可 ...

  3. Netsharp快速入门(之3) 基础档案(之B 实体建模 新建项目)

    作者:秋时 杨昶   时间:2014-02-15  转载须说明出处 3.3     创建业务模型 3.3.1  新建项目 1.打开业务模型 2.打开业务模型后,在工具栏上选择操作-新增项目分类,标识这 ...

  4. hdu 4858 项目管理 图的分块

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4858 我们建造了一个大项目!这个项目有n个节点,用很多边连接起来,并且这个项目是连通的!两个节点间可能 ...

  5. 导入ApiDemo报错,找不到R文件

    1.先检查当前ApiDemo对应的SDK版本是否一致(项目右键-Properties-Android) 2.查看是什么错误.我的就是layout中的progressbar_2.xml中所有组件的id前 ...

  6. js 调用IE内置打印控件

    转自学网(http://www.xue5.com/itedu/200802/102909.html) WebBrowser是IE内置的浏览器控件,无需用户下载. 一.WebBrowser控件 < ...

  7. 对于Linux平台下C语言开发中__sync_函数的认识

      reference:http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html#Atomic-Builtins A built ...

  8. Python并发与并行的新手指南

    点这里 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global interpreter lock(也被亲切的称为“GIL”)指指点点,说它阻碍了Python的多线程 ...

  9. ubuntu安装hive

    1.安装mysql,可参考下面链接 http://www.cnblogs.com/liuchangchun/p/4099003.html 2.安装hive,之前,先在mysql上创建一个hive,数据 ...

  10. 关于解压覆盖IIS文件后,新的文件不具备权限导致DMS系统无法正常运行

     向DMS的服务器端站点bin目录覆盖任何补丁文件,请注意:Web站点的bin目录中的文件,IIS的服务进程(Windows2003以上,都是对应Network Services账户)必须对这些文件具 ...