博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
程序员面试题精选100题(33)-在O(1)时间删除链表结点[数据结构]
阅读量:4622 次
发布时间:2019-06-09

本文共 2173 字,大约阅读时间需要 7 分钟。

作者:何海涛

出处:

题目:给定链表的头指针和一个结点指针,在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)给定的要删除的结点不是链表的头结点。不考虑第一个假设对代码的鲁棒性是有影响的。至于第二个假设,当整个列表只有一个结点时,代码会有问题。但这个假设不算很过分,因为在有些链表的实现中,会创建一个虚拟的链表头,并不是一个实际的链表结点。这样要删除的结点就不可能是链表的头结点了。当然,在面试中,我们可以把这些假设和面试官交流。这样,面试官还是会觉得我们考虑问题很周到的。

作者:何海涛

出处:

转载于:https://www.cnblogs.com/liushaobo/p/4373797.html

你可能感兴趣的文章
pattern与matcherr
查看>>
《java基础知识》Java 运算符
查看>>
C# 如何实现记住密码功能
查看>>
服务器与wp7的socket通信【转】 http://www.cnblogs.com/linzheng/archive/2011/06/21/2086456.html...
查看>>
oschina 客户端源码解析 【转】http://blog.csdn.net/wangchun8926/article/category/1315637
查看>>
Mac OS删除文件夹和文件的命令
查看>>
MyBatis中<![CDATA[ ]]>的使用
查看>>
SpringBoot+Vue(2)
查看>>
Tornado之抽屉实战(1)--分析与架构
查看>>
树莓派进阶之路 (017) - 树莓派的专用摄像头实现局域网监控
查看>>
使用mysql作为hive的元数据库
查看>>
插入排序算法
查看>>
数组运用_1-11 选择题
查看>>
python名片管理系统
查看>>
浅谈虚拟DOM
查看>>
跨站脚本攻击XSS
查看>>
在线HTTP POST/GET接口测试工具 - aTool在线工具
查看>>
js修改样式表规则
查看>>
php常用字符串数组函数
查看>>
Desired capabilities参数配置说明
查看>>