如何在O(1)的时间里删除单链表的结点
2017-05-10 01:33
471 查看
题目是这样的:给你一个单链表的表头,再给你其中某个结点的指针,要你删除这个结点,条件是你的程序必须在O(1)的时间内完成删除。
由于有的同学对链表还不是很熟悉,本文尽量描述的通俗易懂,老鸟请直接跳过前面一大段。
链表结构如下:
题目不是很难,很快就能想到好办法:)
首先回顾一下普通的删除方法,首先通过表头,找到待删除结点(设为B)的前一个结点(设为A),将A的指向改一下就行,然后删除掉B结点就行了。要删除的结点一定要delete掉,这不仅是个好习惯,而且能避免将来项目中可能造成的内存泄露的严重问题。
这个算法主要耗时在于查找前一个结点,所以是O(n)的算法。
那么既然要求是O(1),显然不能再去for一遍了,联想到数组的删除,这个问题就比较好解决了。
首先我们很容易就能得到待删除结点,即B结点的后一个结点C,然后将C的值赋值给B结点的值,相当于数组删除时候的覆盖,现在B结点和C结点一模一样了,接下来就相当简单了吧,我们不删B,直接利用B删掉C就行了,方法简单,时间O(1)。
但是仔细想想这个算法有个很明显的缺陷,如果待删除结点是最后一个结点呢?这个时候似乎没有什么好的解决办法,只能老老实实的O(n)了。现在我们来看看平均时间复杂度:
符合题目要求。
最后附上完整测试代码:
由于有的同学对链表还不是很熟悉,本文尽量描述的通俗易懂,老鸟请直接跳过前面一大段。
链表结构如下:
struct node { int val; node* next; };
题目不是很难,很快就能想到好办法:)
首先回顾一下普通的删除方法,首先通过表头,找到待删除结点(设为B)的前一个结点(设为A),将A的指向改一下就行,然后删除掉B结点就行了。要删除的结点一定要delete掉,这不仅是个好习惯,而且能避免将来项目中可能造成的内存泄露的严重问题。
void DeleteNode_On(node *LinkList, node *p) { printf("delete:%d\n", p->val); node *s = LinkList; while(s->next != p) s = s->next; s->next = s->next->next; delete(p); }
这个算法主要耗时在于查找前一个结点,所以是O(n)的算法。
那么既然要求是O(1),显然不能再去for一遍了,联想到数组的删除,这个问题就比较好解决了。
首先我们很容易就能得到待删除结点,即B结点的后一个结点C,然后将C的值赋值给B结点的值,相当于数组删除时候的覆盖,现在B结点和C结点一模一样了,接下来就相当简单了吧,我们不删B,直接利用B删掉C就行了,方法简单,时间O(1)。
但是仔细想想这个算法有个很明显的缺陷,如果待删除结点是最后一个结点呢?这个时候似乎没有什么好的解决办法,只能老老实实的O(n)了。现在我们来看看平均时间复杂度:
符合题目要求。
void DeleteNode_O1(node *LinkList, node *p) { printf("delete:%d\n", p->val); if(p->next != NULL) //如果p不是末尾结点, 则让后一个结点覆盖掉p, 然后删除后一个结点 { p->val = p->next->val; node *tmp = p->next; p->next = p->next->next; delete(tmp); } else // 如果p是末尾结点, 则找到p的前一个结点然后正常删除 { node *s = LinkList; while(s->next != p) s = s->next; s->next = s->next->next; delete(p); } }
最后附上完整测试代码:
#include<iostream>
using namespace std;
struct node { int val; node* next; };
void CreateLinkList(node *LinkList)
{
node *s = LinkList;
for(int i = 0; i < 10; i++)
{
node *t = new node;
t->val = i;
t->next = NULL;
s = s->next = t;
}
}
void ShowLinkList(node * LinkList)
{
node *s = LinkList->next;
while(s = s->next)
printf("%d ", s->val);
putchar(10);
}
void DeleteNode_On(node *LinkList, node *p) { printf("delete:%d\n", p->val); node *s = LinkList; while(s->next != p) s = s->next; s->next = s->next->next; delete(p); }
void DeleteNode_O1(node *LinkList, node *p) { printf("delete:%d\n", p->val); if(p->next != NULL) //如果p不是末尾结点, 则让后一个结点覆盖掉p, 然后删除后一个结点 { p->val = p->next->val; node *tmp = p->next; p->next = p->next->next; delete(tmp); } else // 如果p是末尾结点, 则找到p的前一个结点然后正常删除 { node *s = LinkList; while(s->next != p) s = s->next; s->next = s->next->next; delete(p); } }
int main()
{
node *LinkList = new node;
CreateLinkList(LinkList);
ShowLinkList(LinkList);
node *p = LinkList->next;
for(int i = 0; i < 3; i++)
p = p->next;
DeleteNode_On(LinkList, p);
ShowLinkList(LinkList);
p = LinkList->next;
for(int i = 0; i < 8; i++)
p = p->next;
DeleteNode_O1(LinkList, p);
ShowLinkList(LinkList);
p = LinkList->next;
for(int i = 0; i < 4; i++)
p = p->next;
DeleteNode_O1(LinkList, p);
ShowLinkList(LinkList);
getchar();
return 0;
}
void DeleteNode(ListNode** pHead, ListNode* pToBeDeleted){//删除链接节点算法 时间复杂度为O(1); if (!pHead || !pToBeDeleted) { return; } if (pToBeDeleted->m_pNext != NULL) { ListNode* pNext = pToBeDeleted->m_pNext; pToBeDeleted->m_nValue = pNext->m_nValue; pToBeDeleted->m_pNext = pNext->m_pNext; delete pNext; pNext = NULL; } else if (*pHead ==pToBeDeleted) { delete pToBeDeleted; pToBeDeleted = NULL; *pHead = NULL; } else { ListNode* pNode = *pHead; while (pNode->m_pNext != pToBeDeleted) { pNode = pNode->m_pNext; } pNode->m_pNext = NULL; delete pToBeDeleted; pToBeDeleted = NULL; } } void Test(ListNode* pListHead, ListNode* pNode){ printf("the original list is:\n"); PrintList(pListHead); printf("The node to be deleted is:\n"); PrintList(pNode); DeleteNode(&pListHead, pNode); printf("the result list is:\n"); PrintList(pListHead); } void Test1(){ ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); CoonnectListNode(pNode1, pNode2); CoonnectListNode(pNode2, pNode3); CoonnectListNode(pNode3, pNode4); CoonnectListNode(pNode4, pNode5); Test(pNode1, pNode5); DestroyList(pNode1); }
相关文章推荐
- [算法浅析] 如何在O(1)的时间里删除单链表的结点
- [算法浅析] 如何在O(1)的时间里删除单链表的结点
- 【数据结构】单链表—在O(1)时间删除链表结点
- 在 O(1) 的时间内删除单链表的结点
- 在O(1)时间内删除单链表结点
- 在O(1)时间内删除单链表结点
- 剑指offer算法题之单链表的删除结点操作--面试题13:在O(1)时间删除链表结点
- 在O(1)时间内删除单链表结点
- mtk笔试题-----快速删除单链表中一个结点。时间复杂度为o(1)
- 面试题13:在O(1)时间删除单链表结点
- 设一个没有头结点指针的单链表。一个指针指向此单链表中间的一个结点(不是第一个,也不是最后一个结点),将该结点从单链表中删除,要求时间复杂度O(1)。
- 在O(1)时间删除单链表结点
- 在O(1)时间内删除单链表结点
- 时间复杂度分别为 O(n)和 O(1)的删除单链表结点的方法
- 面试题:如何删除单链表的重复结点
- 4,常数时间内删除单链表中某结点
- 在O(1)时间内删除链表结点
- 在O(1)平均时间删除链表结点 [# 13]
- 时间复杂度为O(1)的删除链表结点方法
- 数据结构题典002:删除单链表中最大元素所在结点(ANSI C)