题目:给定链表的头指针和一个结点指针,在O(1)平均时间删除该结点。链表结点的定义如下:
structListNode
{
intm_nKey;
ListNode*m_pNext;
};
函数的声明如下:
voidDeleteNode(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)。
基于前面的分析,我们不难写出下面的代码。
参考代码:
值得注意的是,为了让代码看起来简洁一些,上面的代码基于两个假设:(1)给定的结点的确在链表中;(2)给定的要删除的结点不是链表的头结点。不考虑第一个假设对代码的鲁棒性是有影响的。至于第二个假设,当整个列表只有一个结点时,代码会有问题。但这个假设不算很过分,因为在有些链表的实现中,会创建一个虚拟的链表头,并不是一个实际的链表结点。这样要删除的结点就不可能是链表的头结点了。当然,在面试中,我们可以把这些假设和面试官交流。这样,面试官还是会觉得我们考虑问题很周到的。
转自:http://zhedahht.blog.163.com/blog/static/254111742007112255248202/
分享到:
相关推荐
14. **链表插入时间复杂度**:对于单链表,在表头插入元素的时间复杂度为\(O(1)\),因为只需要改变头结点的`next`指针即可;而在表尾插入的时间复杂度为\(O(n)\),因为需要遍历整个链表找到尾部。 15. **二维数组的...
7. 在顺序表中删除一个元素,最少移动0个元素(如果删除的是最后一个元素),最多移动99个元素,平均移动49.5个元素。 8. 使用Hash表查找的理想情况是常数时间复杂度O(1),因为直接通过哈希函数定位元素。 9. 对于...
在数组中删除一个元素平均需要将该元素后面的所有元素向前移动一位,因此平均移动次数为(n-1)/2。 **18. 设循环队列的容量为50(序号从0到49),现经过一系列的入队和出队运算后,有①front=11,rear=29;②front=29...
在算法复杂度方面,除了求线性表长度是O(1)外,其他操作如插入、删除、逆置等都为O(n),其中n是链表的长度。这是因为这些操作需要遍历链表的大部分或全部节点。 在源程序中,`initList`函数用于初始化链表,`...
双链表中,可以删除该结点,时间复杂度为 O(1)。单循环链表中,可以删除该结点,时间复杂度为 O(n)。 6. 下述算法的功能是什么: 该算法的功能是:将开始结点摘下链接到终端结点之后成为新的终端结点,而原来的第...
- 双链表:可以删除,时间复杂度为O(1),因为可以访问前后结点。 - 单循环链表:可以删除,但需要查找前趋结点,时间复杂度为O(n)。 6. 算法`LinkList Demo`的功能: 此算法将链表的开始结点移到链表末尾,成为...
而在单链表中,删除一个已知结点*p需要找到它的前驱结点,时间复杂度为O(n)。 5. 链表的特点:顺序表中逻辑上相邻的元素在物理位置上必定相邻,而单链表中则不一定。这体现了链表的灵活性,但同时也增加了查找操作...
答案是,双链表可以在O(1)时间内删除结点,单链表和单循环链表无法删除结点,但单循环链表可以在O(n)时间内删除结点。 在算法 Demo 中,算法将开始结点摘下链接到终端结点之后成为新的终端结点,而原来的第二个结点...
双链表中,由于双向链接,可以找到前趋和后继,所以删除结点的时间复杂度为O(1);单循环链表中,通过查找可以删除结点,但时间复杂度为O(n)。 6. 提供的算法Demo将链表的开始结点连接到原链表的终端结点后面,形成...
- 尾指针能快速定位到链表的终端结点,查找时间是 O(1),而用头指针查找终端结点需要 O(n)。 5. 结点删除: - 单链表:不能直接删除,因为无法访问前驱结点。 - 双链表:可以删除,时间复杂度 O(1),因为可以...
在链表中,访问第i个元素需要从头结点开始遍历,直到找到第i-1个元素的后继,这使得链表不适合于需要快速访问任意位置元素的场景。 总结来说,线性表是数据结构的基础,其顺序存储和链式存储各有优缺点。顺序表适合...
解析:快速排序在最坏情况下的空间复杂度为O(n),而在平均情况下为O(log2n),这主要取决于递归调用栈的深度。 #### 24. 数据的最小单位是()。 **答案:A. 数据项** 解析:数据项是最小的数据单位,通常指的是...
- **单链表和单循环链表**:删除某个结点的时间复杂度为O(n),因为在找到待删除结点前需要遍历链表。 - **单循环链表中尾指针的重要性**: - 使用尾指针可以在O(1)时间内完成在表尾插入元素或删除第一个元素的操作...
用它来表示单循环链表可以使得查找链表的开始结点和终端结点都很方便,设一带头结点的单循环链表,其尾指针为rear,则开始结点和终端结点的位置分别是rear->next->next和rear,查找时间都是O(1)。 5. 单链表、双...
在实现这些功能时,会涉及到数据结构的选择、内存管理、文件I/O等技术。例如,为了提高查询效率,可以使用二分查找法或哈希映射;为了持久化数据,需要将struct对象序列化到文件,下次启动程序时再反序列化。 此外...
在顺序表中插入或删除一个结点,平均需要移动n/2个结点。移动的具体次数取决于插入或删除的位置以及表的当前长度。如果操作发生在表的末尾,移动次数最少;如果发生在表的开头,移动次数最多。 **链表的有序性与...
- 时间复杂度:在p所指结点后插入新结点的时间复杂度为O(1),因为只修改指针;在给定值x的结点后插入新结点的时间复杂度为O(n),因为需要遍历找到x。 3. **链表类型**: - 可由尾指针唯一确定的链表包括循环链表...
在顺序表中插入和删除元素的平均时间复杂度为O(n/2),而在链表中,找到结点的前驱所需时间是O(n)。 5. **存储结构的选择**:顺序存储结构(如数组)存储密度大,但插入和删除操作效率低,适合静态或变化不频繁的...
在顺序表中,元素在物理存储上是连续的,这使得访问任意元素的时间复杂度为O(1),但插入和删除操作通常需要移动大量元素,时间复杂度为O(n)。例如,向长度为n的顺序表中插入一个元素,平均需要移动n/2个元素;删除...