剑指offer| |在O(1)时间删除链表结点

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

思路:对于该题可以采用替换删除法。
对于链表有多个结点:
即要删除该结点的可以将其后面的结点的数据域给该结点,然后删除后面的结点。
这个方法有一个bug那就是比如要删除的结点是尾结点的话,那么其后面就没有结点可供让其替换删除的了,所以对于删除尾结点的话,还是采用遍历到该结点的前一节点然后再进行删除即可。
链表有一个节点:
如果链表有一个结点:
那么删除的结点就既是头结点也是尾结点,只需要将头指针的next域置空,在释放掉要删除的结点即可。

代码:

void DeleteNode(pList* phead, pNode pos)
{
    assert(phead && pos);

    //删除的不是尾结点(并且结点个数大于1if (pos->next != NULL)
    {
        pNode del = pos->next;
        pos->data = del->data;
        pos->next = del->next;

        free(del);
        del = NULL;
    }
    //链表只有一个结点,删除的是头结点,也是尾结点
    else if (*phead == pos)
    {
        pNode del = pos;
        *phead = NULL;

        free(del);
        del = NULL;
    }
    //链表中有多个节点,删除的是尾结点
    else
    {
        pNode cur = *phead;

        while (cur->next != pos)
        {
            cur = cur->next;
        }

        cur->next = pos->next;
        free(pos);
        pos = NULL;
    }
}

这一代码是基于前面写的链表的基本操作里面定义的结构体写的,大家可以参考前面的结构体观看。链接地址:https://blog.csdn.net/qq_40399012/article/details/81742603

接下来我们分析这种思路的时间复杂度,对于n-1个非尾结点而言,我们可以在O(1)时把下一个结点的内存覆盖到要删除的结点,并删除下一个节点:对于尾结点来说由于仍要顺序查找,时间复杂度是O(n),因此平均复杂度是[(n - 1) * O(1) + O(n)] / n,结果还是O(1。

值得注意的是上面的代码仍不是一个完美的代码:因为它基于一个假设,要删除的结点的确在链表中,我们需要O(n)的时间才能知道链表中是否包含某一节点。受到时间复杂度我们不得不把确保要删除的结点在链表中的责任推给了函数DeleteNode的调用者。

猜你喜欢

转载自blog.csdn.net/qq_40399012/article/details/82257176
今日推荐