剑指offer--用O(1)的时间复杂度删除链表的节点

面试题13:给定单项链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。

//不带头结点的单链表
struct ListNode
{
    int m_nKey;
    ListNode *m_pNext;
};

//尾插
void InsertTail(ListNode **head,int key)
{
    ListNode *newnode = new ListNode();
    newnode->m_nKey = key;
    newnode->m_pNext = NULL;

    if(*head == NULL)
    {
        *head = newnode;
    }
    else
    {
        ListNode *p = *head;
        while(p->m_pNext != NULL)
            p = p->m_pNext;

        p->m_pNext = newnode;
    }
}

/*假设该结点在链表中。
如果不假设,我们需要O(n)的时间才能判断链表中是否包含该结点。基于O(1)的限制,只能把确保结点在链表中的要求推给函数调用者*/
void DeleteNode(ListNode **head,ListNode *deletenode)
{
    if(head==NULL || deletenode==NULL)
        return;
    //删除的节点不是尾节点
    if(deletenode->m_pNext != NULL)
    {
        ListNode *p = deletenode->m_pNext;
        deletenode->m_nKey = p->m_nKey;
        deletenode->m_pNext = p->m_pNext;
        delete(p);
        p = NULL;
    }
    //链表只有一个节点,删除的是尾节点
    else if(*head == deletenode)
    {
        delete deletenode;
        deletenode = NULL;
        *head = NULL;
    }
    //链表有多个节点,删除的是尾节点
    else
    {
        ListNode *p = *head;
        while(p->m_pNext != deletenode)
        {
             p = p->m_pNext;
        }
        p->m_pNext = NULL;

        delete deletenode;
        deletenode = NULL;
    }
}

void Show(ListNode *head)
{
    for(ListNode *p=head;p!=NULL;p=p->m_pNext)
    {
        cout<<p->m_nKey<<ends;
    }
    cout<<endl;
}

int main()
{
    ListNode *head = NULL;
    for(int i=0;i<10;i++)
    {
        InsertTail(&head,i);
    }
    cout<<"删除前:";
    Show(head);

    cout<<"删除第三个元素:";
    DeleteNode(&head,head->m_pNext->m_pNext);
    Show(head);

    cout<<"删除首元素:";
    DeleteNode(&head,head);
    Show(head);

    ListNode *p = head;
    while(p->m_pNext != NULL) p = p->m_pNext;
    cout<<"删除尾元素:";
    DeleteNode(&head,p);
    Show(head);
}

这里写图片描述

对于一个n-1非尾结点而言,可以在O(1)时把下一个结点的内存复制覆盖要删除的结点,并删除下一个结点;对于尾结点来说,由于仍需要顺序查找,时间复杂度为O(n)。总的时间复杂度是[(n-1)*O(1)+O(n)]/n,结果是O(1)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值