0
点赞
收藏
分享

微信扫一扫

每日一算: 在时间复杂度O(1)下删除单链表中节点


背景

今天做到一道题:设一个有序的单链表中有n个节点,现要求插入一个新节点后是的单链表仍保持有序,则该操作的时间为:。

答案是:O(n)
为什么?
因为它是链表!
链表的增删改功能,一定依托于其“low的一批”的“ 遍历 ”,这是链表的核心。插入一个数据,就要遍历一遍,有n个节点,时间复杂度就是O(n)。

为什么强调是“单链表”呢?
因为在实际的软件开发中,从链表中删除一个数据无外乎这两种情况:
删除结点中“值等于某个给定值”的结点
删除给定指针指向的结点

针对第二种情况,单链表删除操作需要 O(n) 的时间复杂度,而双向链表只需要在 O(1) 的时间复杂度。

冰火两重天:时空复杂度O()

这一部分我自认为没有能力讲解清楚,相比自己,我更想为大家推荐一篇文章(@程序员小吴):​​冰与火之歌:时间与空间复杂度​​

正文:问题描述

给定一个单链表中的表头和一个等待被删除的节点。请在 O(1) 时间复杂度删除该链表节点。并在删除该节点后,返回表头。

示例:
给定 1->2->3->4,和节点 3,返回 1->2->4。

解题思想

在之前介绍的单链表删除节点中,最普通的方法就是遍历链表,复杂度为O(n)。
如果我们把删除节点的下一个结点的值赋值给要删除的结点,然后删除这个结点,这相当于删除了需要删除的那个结点。因为我们很容易获取到删除节点的下一个节点,所以复杂度只需要O(1)。

示例:
单链表:1->2->3->4->NULL
若要删除节点 3 。第一步将节点3的下一个节点的值4赋值给当前节点。变成 1->2->4->4->NULL,然后将就 4 这个结点删除,就达到目的了。 1->2->4->NULL
如果删除的节点的是头节点,把头结点指向 NULL。
如果删除的节点的是尾节点,那只能从头遍历到头节点的上一个结点。

代码展示:

void deleteNode(ListNode **pHead, ListNode* pDelNode) {
if(pDelNode == NULL)
return;
if(pDelNode->next != NULL){
ListNode *pNext = pDelNode->next;
//下一个节点值赋给待删除节点
pDelNode->val = pNext->val;
//待删除节点指针指后面第二个节点
pDelNode->next = pNext->next;
//删除待删除节点的下一个节点
delete pNext;
pNext = NULL;
}else if(*pHead == pDelNode)//删除的节点是头节点
{
delete pDelNode;
pDelNode= NULL;
*pHead = NULL;
} else//删除的是尾节点
{
ListNode *pNode = *pHead;
while(pNode->next != pDelNode) {
pNode = pNode->next;
}
pNode->next = NULL;
delete pDelNode;
pDelNode= NULL;
}
}


举报

相关推荐

0 条评论