您的位置:首页 > 其它

[算法浅析] 如何在O(1)的时间里删除单链表的结点

2014-08-02 09:00 483 查看
题目是这样的:给你一个单链表的表头,再给你其中某个结点的指针,要你删除这个结点,条件是你的程序必须在O(1)的时间内完成删除。

由于有的同学对链表还不是很熟悉,本文尽量描述的通俗易懂,老鸟请直接跳过前面一大段。

链表结构如下:

[cpp] view
plaincopyprint?

struct node

{

int val;

node* next;

};

题目不是很难,很快就能想到好办法:)

首先回顾一下普通的删除方法,首先通过表头,找到待删除结点(设为B)的前一个结点(设为A),将A的指向改一下就行,然后删除掉B结点就行了。要删除的结点一定要delete掉,这不仅是个好习惯,而且能避免将来项目中可能造成的内存泄露的严重问题。



[cpp] view
plaincopyprint?

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)了。现在我们来看看平均时间复杂度:



符合题目要求。

[cpp] view
plaincopyprint?

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);

}

}

最后附上完整测试代码:

[cpp] view
plaincopyprint?

#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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: