O(1)时间内删除指定链表结点
题目
给定单链表头指针和一个结点指针,定义一个函数在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有两个特例:
- 删除的是尾指针,需要遍历找到前一个指针
- 整个链表就一个结点(属于删尾指针,但没法找到前面的指针,需要开小灶单独处理)
大体算法思路
待删指针不是尾指针:
待删指针的值用待删指针的下一个指针的值覆盖
删掉待删指针的下一个指针
待删指针是尾指针:
待删指针同时是头指针:
删掉头指针
待删指针不是头指针
找到待删指针的前一个指针
删掉待删指针,前一个指针的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)时间内删除指定链表结点的更多相关文章
- 在O(1)时间内删除单链表结点
// 在O(1)时间内删除单链表结点 /* 思考: 很显然链表是一个节点地址不连续的存储结构 删除节点一般很容易会想到是修改p节点的前一个节点的next为p->next 然而除非是双向链表,否则 ...
- 在O(1)时间删除指定链表结点
#region 在O(1)时间删除指定链表结点 /// <summary> /// 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. /// </summa ...
- 在O(1)时间内删除单链表结点
给定单链表的一个结点的指针,同时该结点不是尾结点,此外没有指向其它任何结点的指针,请在O(1)时间内删除该结点. int deleteNode(LNode **head, LNode **node) ...
- 时间复杂度分别为 O(n)和 O(1)的删除单链表结点的方法
有一个单链表,提供了头指针和一个结点指针,设计一个函数,在 O(1)时间内删除该结点指针指向的结点. 众所周知,链表无法随机存储,只能从头到尾去遍历整个链表,遇到目标节点之后删除之,这是最常规的思路和 ...
- 13:在O(1)时间内删除单向链表中的一个节点
思路:如果从首部开始依次查找,那么时间是O(n). 既然我们知道要删除的结点i,那么我们就知道它指向的下一个结点j,那么我们可以将j的内容复制到i,然后将i的指针指向j的下一个结点,这样虽然看起来我们 ...
- 《剑指offer》面试题13—O(1)时间删除链表结点
题目:给定单向链表的头指针和某结点指针,实现函数在O(1)时间内删除指定节点. 思路:由于没有要删除结点(j结点)的前一个结点(i结点)指针,通常想法是从头开始遍历找到指定结点的前一个结点(i结点), ...
- pta 奇数值结点链表&&单链表结点删除
本题要求实现两个函数,分别将读入的数据存储为单链表.将链表中奇数值的结点重新组成一个新的链表.链表结点定义如下: struct ListNode { int data; ListNode *next; ...
- 【编程题目】在 O(1)时间内删除链表结点
60.在 O(1)时间内删除链表结点(链表.算法).题目:给定链表的头指针和一个结点指针,在 O(1)时间删除该结点.链表结点的定义如下:struct ListNode{int m_nKey;List ...
- (剑指Offer)面试题13:在O(1)时间内删除链表结点
题目: 在给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间内删除该结点.链表结点与函数的定义如下: struct ListNode{ int val; ListNode* next; } ...
随机推荐
- mailx 乱码,sendmail发html邮件,脚本开机启动
echo "yes"|mailx -s "我" -S ttycharset=utf-8 -S sendcharsets=utf-8 -S encoding=ut ...
- Navicat Premium 11.0.19中文破解版 安装
一.navicat-premium简介 它是一款可连接多种数据库的软件,具体参见官网介绍:http://www.navicat.com.cn/products/navicat-premium 二.下载 ...
- 【python】文件的输入和输出
1.os模块 2.os.path 模块 3.实例 1. os模块 对文件系统的访问大多通过python的os模块实现,其中os 模块负责大部分的文件系统操作,包括删除/重命名文件,遍历目录树,管理文件 ...
- c++ 继承和组合的区别
.什么是继承 A继承B,说明A是B的一种,并且B的所有行为对A都有意义 eg:A=WOMAN B=HUMAN A=鸵鸟 B=鸟 (不行),因为鸟会飞,但是鸵鸟不会. .什么是组合 若在逻辑上A是B的“ ...
- jquery 常用组件的小代码
获得所有复选框的值 function getAllValue() { var str=""; $("input[name='checkbox']:checkbox&quo ...
- JS的基础语法
8.运算符号表达式 ①数学运算符 数学运算符有+.-.*./除().%(余数) var a = 10; var b = 5; alert(a+b); 预览以后在网页上弹出的对话框数值就是15. ②逻辑 ...
- Http Module 介绍
引言 Http 请求处理流程 和 Http Handler 介绍 这两篇文章里,我们首先了解了Http请求在服务器端的处理流程,随后我们知道Http请求最终会由实现了IHttpHandler接口的类进 ...
- wordpress无法安装这个包。: PCLZIP_ERR_MISSING_FILE (-4) : Missing archive file 'C:\WINDOWS\TEMP/wordpress-4.tmp'
朋友的wp博客好久没管理了,让ytkah帮忙打理一下,进到后台发现版本还是3.9的,那是比较早以前的版本了,早该升级了. 在升级wordpress时出现以下错误: 无法安装这个包: PCLZIP_ER ...
- var 和 dynamic在实际项目中的应用
先回顾一下这两个关键词的用法. var是个语法糖,是在用var声明变量的那一刻就确定了其变量的类型. 因为需要在声明的时候就确定其类型,所以要求在用var声明隐式局部变量的时候必须初始化该变量. 编译 ...
- oracle impdp的table_exists_action详解
oracle impdp的table_exists_action详解 分类: [oracle]--[备份与恢复]2012-01-06 22:44 9105人阅读 评论(0) 收藏 举报 tableac ...