如何在O(1)的时间里删除单链表的结点

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

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

链表结构如下:

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

}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值