程序员面试题精选100题(33)-在O(1)时间删除链表结点[数据结构]
作者:何海涛
出处:http://zhedahht.blog.163.com/
题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点。链表结点的定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
函数的声明如下:
void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted);
分析:这是一道广为流传的Google面试题,能有效考察我们的编程基本功,还能考察我们的反应速度,更重要的是,还能考察我们对时间复杂度的理解。
在链表中删除一个结点,最常规的做法是从链表的头结点开始,顺序查找要删除的结点,找到之后再删除。由于需要顺序查找,时间复杂度自然就是O(n)
了。
我们之所以需要从头结点开始查找要删除的结点,是因为我们需要得到要删除的结点的前面一个结点。我们试着换一种思路。我们可以从给定的结点得到它的下一个结点。这个时候我们实际删除的是它的下一个结点,由于我们已经得到实际删除的结点的前面一个结点,因此完全是可以实现的。当然,在删除之前,我们需要需要把给定的结点的下一个结点的数据拷贝到给定的结点中。此时,时间复杂度为O(1)。
上面的思路还有一个问题:如果删除的结点位于链表的尾部,没有下一个结点,怎么办?我们仍然从链表的头结点开始,顺便遍历得到给定结点的前序结点,并完成删除操作。这个时候时间复杂度是O(n)。
那题目要求我们需要在O(1)时间完成删除操作,我们的算法是不是不符合要求?实际上,假设链表总共有n个结点,我们的算法在n-1总情况下时间复杂度是O(1),只有当给定的结点处于链表末尾的时候,时间复杂度为O(n)。那么平均时间复杂度[(n-1)*O(1)+O(n)]/n,仍然为O(1)。
基于前面的分析,我们不难写出下面的代码。
参考代码:
///////////////////////////////////////////////////////////////////////
// Delete a node in a list
// Input: pListHead - the head of list
// pToBeDeleted - the node to be deleted
///////////////////////////////////////////////////////////////////////
void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted)
{
if(!pListHead || !pToBeDeleted)
return;
// if pToBeDeleted is not the last node in the list
if(pToBeDeleted->m_pNext != NULL)
{
// copy data from the node next to pToBeDeleted
ListNode* pNext = pToBeDeleted->m_pNext;
pToBeDeleted->m_nKey = pNext->m_nKey;
pToBeDeleted->m_pNext = pNext->m_pNext;
// delete the node next to the pToBeDeleted
delete pNext;
pNext = NULL;
}
// if pToBeDeleted is the last node in the list
else
{
// get the node prior to pToBeDeleted
ListNode* pNode = pListHead;
while(pNode->m_pNext != pToBeDeleted)
{
pNode = pNode->m_pNext;
}
// deleted pToBeDeleted
pNode->m_pNext = NULL;
delete pToBeDeleted;
pToBeDeleted = NULL;
}
}
值得注意的是,为了让代码看起来简洁一些,上面的代码基于两个假设:(1)给定的结点的确在链表中;(2)给定的要删除的结点不是链表的头结点。不考虑第一个假设对代码的鲁棒性是有影响的。至于第二个假设,当整个列表只有一个结点时,代码会有问题。但这个假设不算很过分,因为在有些链表的实现中,会创建一个虚拟的链表头,并不是一个实际的链表结点。这样要删除的结点就不可能是链表的头结点了。当然,在面试中,我们可以把这些假设和面试官交流。这样,面试官还是会觉得我们考虑问题很周到的。
作者:何海涛
出处:http://zhedahht.blog.163.com/
程序员面试题精选100题(33)-在O(1)时间删除链表结点[数据结构]的更多相关文章
- 程序员面试题精选100题(16)-O(logn)求Fibonacci数列[算法]
作者:何海涛 出处:http://zhedahht.blog.163.com/ 题目:定义Fibonacci数列如下: / 0 n=0 f(n)= ...
- 程序员面试题精选100题(38)-输出1到最大的N位数[算法]
作者:何海涛 出处:http://zhedahht.blog.163.com/ 题目:输入数字n,按顺序输出从1最大的n位10进制数.比如输入3,则输出1.2.3一直到最大的3位数即999. 分析:这 ...
- 《剑指offer》第十八题(在O(1)时间删除链表结点)
// 面试题18(一):在O(1)时间删除链表结点 // 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该 // 结点. #include <iostream> ...
- 33.在O(1)时间删除链表结点[DeleteListNode]
[题目] 给定链表的头指针和一个结点指针,在O(1)时间删除该结点.链表结点的定义如下: C++ Code 123456 struct ListNode { int m_ ...
- 【面试题013】在O(1)时间删除链表结点
[面试题013]在O(1)时间删除链表结点 我们要删除结点i,我们可以把结点i的下一个结点j的内容复制到结点i,然后呢把结点i的指针指向结点j的下一个结点.然后在删除结点j. 1.如果结点i位于链表 ...
- 面试题18(一):在O(1)时间删除链表结点
// 面试题18(一):在O(1)时间删除链表结点 // 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该 // 结点.链表结点与函数的定义如下: // struct Lis ...
- [经典面试题]在O(1)时间删除链表结点
[题目] 给定链表的头指针和一个结点指针.在O(1)时间删除该结点.链表结点的定义例如以下: struct ListNode { int value; struct ListNode* ...
- 剑指Offer面试题:12.在O(1)时间删除链表结点
一.题目:在O(1)时间删除链表结点 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. 原文采用的是C/C++,这里采用C#,节点定义如下: public class ...
- 剑指Offer:面试题13——在O(1)时间删除链表结点
问题描述: 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点.链表结点与函数的定义如下: public class ListNode{ int value; ListNode ...
随机推荐
- 已知有十六支男子足球队参加2008 北京奥运会。写一个程序,把这16 支球队随机分为4 个组。采用List集合和随机数
package homework002; import java.util.ArrayList; import java.util.List; import java.util.Random; p ...
- Windows 环境下基于 nginx 的本地 PyPI 源
Windows 环境下基于 nginx 的本地 PyPI 源的搭建: 1.登录 nginx 官网,下载安装包
- Asp.net 用 Graphics 统计图(柱状图, 折线图, 扇形图)
统计图形种类繁多, 有柱状图, 折线图, 扇形图等等, 而统计图形的绘制方法也有很多, 有Flash制作的统计图形, 有水晶报表生成统计图形, 有专门制图软件制作, 也有编程语言自己制作的:这里我们用 ...
- 如何调试libc++abi.dylib handler threw exception错误
From:http://blog.csdn.net/naruto_ku/article/details/8779203 在进行iOS开发时,偶尔会碰到libc++abi.dylib handler t ...
- iOS开发——高级技术&密码锁功能的实现
密码锁功能的实现 一个ios手势密码功能实现 ipad/iphone 都可以用 没有使用图片,里面可以通过view自己添加 keychain做的数据持久化,利用苹果官方KeychainItemWrap ...
- 编程之linux与win区别
换行符在Linux和Windows下的区别 一.区别 换行符: 1.windows中的换行符是\r\n, 2. linux/unix下的换行符是\n. 其中: 回车符:\r=0x0d (13) ret ...
- 观锁与悲观锁(Hibernate)
乐观锁与悲观锁 文章转自网上好像是玉米田的,忘记了 锁( locking ) 业务逻辑的实现过程中,往往需要保证数据访问的排他性.如在金融系统的日终结算 处理中,我们希望针对某个 cut-off 时间 ...
- typeid关键字
这么看下去太要命了,有太多东西要学了... 而且视频看起来的确费神,费脑,费耳朵. 所以决定由视频驱动转向代码驱动.主攻vs,c++然后先把界面东西做出来,然后在想后面的东西. 所以今天 [先上来看了 ...
- oracle学习总结2
1:常用的函数 to_date()函数,将字符串转换为日期格式select to_date('2015-09-12','yyyy-MM-dd') from dual; --其中后面的日期格式要和前面要 ...
- 排序并获取index的顺序
//排序并获取index的顺序:4,7,2,9-->9,7,4,2-->4,2,1,3 Array.prototype.getIndex=function(){ var orderLeng ...