【剑指offer】:在O(1)的时间删除链表结点(第13题)

题目描述

给定一个单向链表的头指真和结点指针,定义一个函数在O(1)的时间内删除该结点。链表,链表结点和函数定义如下:

//链表结点
typedef struct ListNode
{
    int m_nValue;
    struct ListNode* next;
}ListNode,*pListNode;
//函数
void DeleteNode(pListNode* pListHead, pListNode pos);

思路分析

常规做法(O(n))

这里写图片描述

假设删除结点pos所指向的结点 i ,我们的常规做法是从*pListHead开始遍历,找到 i 结点前面的那个结点,将那个pos所指向结点的指针域给它前面结点的指针域,然后释放pos所指向的结点,但是这种做法要遍历链表,时间复杂度为O(n),显然不符合条件。

代码实现

void DeleteNode(pListNode* pListHead, pListNode pos)
{
    assert(pListHead != NULL);
    assert(pos != NULL);
    ListNode* cur = *pListHead;
    //删除的结点是尾结点(链表的长度大于等于2)、
    if (pos->next == NULL)
    {
        while (cur->next == pos)
        {
            cur = cur->next;
        }
        cur->next = NULL;
        free(pos);
        pos = NULL;
    }
    //如果链表只要一个结点,正好那个结点是要删除的结点
    else
    {
        *pListHead = NULL;
        free(pos);
        pos = NULL;
    }
}

覆盖数据法(O(1))

以上图作为分析,假设要删除 i 结点,我们可以将先将 i 后边的那个结点的数据域给前面的那个结点的数据域,然后删除后边的那个结点也同样可以达到目的,这样很巧妙的没有去遍历链表。但是这个思路有一个问题就是不能删除尾结点,因为尾结点后边没有可以替换删除的结点了,要删除尾结点只能从头遍历了。

代码实现

void DeleteNode(pListNode* pListHead, pListNode pos)
{
    assert(pListHead != NULL);
    assert(pos != NULL);
    ListNode* cur = *pListHead;
    ListNode* del = NULL;
    //删除的结点是尾结点(链表的长度大于等于2)、
    if (pos->next == NULL)
    {
        while (cur->next == pos)
        {
            cur = cur->next;
        }
        cur->next =NULL;
        free(pos);
        pos = NULL;
    }
    //如果链表只要一个结点,正好那个结点是要删除的结点
    else if (*pListHead == pos)
    {
        *pListHead = NULL;
        free(pos);
        pos = NULL;
    }
    //删除的结点不是尾结点(链表的长度大于等于2)
    else
    {
        del = pos->next;
        pos->m_nValue = del->m_nValue;
        pos->next = del->next;
        free(del);
        del = NULL;
    }
}

猜你喜欢

转载自blog.csdn.net/hansionz/article/details/80934410
今日推荐