【算法】删除链表的结点

版权声明:本文为博主原创学习笔记,如需转载请注明来源。 https://blog.csdn.net/SHU15121856/article/details/82423334

面试题18:删除链表的结点

在O(1)时间内删除链表结点

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

如果从表头开始找到这个结点(指针一样就是找到),需要O(n)的时间,但能确保这个结点就是在这个链表里。可以考虑将下一结点复制到该结点,再将下一结点删除,除了删除末尾结点不能这样做之外,其他情况都是O(1),平均也是O(1),不过需要调用者能确保这个结点就是在这个链表中。

#include<bits/stdc++.h>
#include "../Utilities/List.h"
using namespace std;

// 参数:
//        pListHead:      指向头结点指针的指针 
//        pToBeDeleted:   指向要删除的结点的指针 
void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) {
    if(!pListHead || !pToBeDeleted)//输入非空检验 
        return;

    //next非空,说明要删除的结点不是尾结点
    if(pToBeDeleted->m_pNext != nullptr) {
        ListNode* pNext = pToBeDeleted->m_pNext;//记录下一结点地址 
        pToBeDeleted->m_nValue = pNext->m_nValue;//将其值覆盖到当前结点 
        pToBeDeleted->m_pNext = pNext->m_pNext;//将当前结点的next指向原下一结点的next,绕过原下一结点 
        delete pNext;//删除刚刚抽出链表的原下一结点即可 
        pNext = nullptr;
    }
    //没满足上个if就说明是尾结点,如果同时还是头结点 
    else if(*pListHead == pToBeDeleted) {
        delete pToBeDeleted;//也就说明只有这一个结点,直接将它删除即可 
        pToBeDeleted = nullptr;
        *pListHead = nullptr;
    }
    //最后一种情况是,在链表中不止一个结点的情形下删除尾结点 
    else {
        ListNode* pNode = *pListHead;//从头结点开始
        //不断向下走,直到走到要删除的结点的前一个结点 
        while(pNode->m_pNext != pToBeDeleted) { 
            pNode = pNode->m_pNext;
        }
        //将该结点next指向空,成为尾结点 
        pNode->m_pNext = nullptr;
        delete pToBeDeleted;//然后删除这个尾结点 
        pToBeDeleted = nullptr;
    }
}
删除链表中重复的结点

在一个排序的链表中,删除重复出现的结点(一个不留)。

两个相邻的结点指针一起走,当走在前面的指针探测到前面有和自己值一样的结点时,让走在后面的结点指针所指向的结点的next指向后面比前面的指针所指向的结点的值大的结点,如此往复。

#include<bits/stdc++.h>
#include "../Utilities/List.h"
using namespace std;

//要删除的结点可能是头结点,所以要传入头结点地址的指针
//否则当删除头结点时,只改形参指针的地址值无法影响到调用者知道的头结点地址 
void DeleteDuplication(ListNode** pHead) {
    //输入非空校验 
    if(pHead == nullptr || *pHead == nullptr)
        return;
    //双指针初始化:第二个从头结点开始,第一个指向它前面的结点(一开始没有) 
    ListNode* pPreNode = nullptr;//前一结点 
    ListNode* pNode = *pHead;//[当前结点]
    //遍历整个链表 
    while(pNode != nullptr) {
        ListNode *pNext = pNode->m_pNext;//探测[当前结点]的下一结点 
        bool needDelete = false;//[当前结点]是否要被删除 
        //如果下一结点存在,且和[当前结点]值相同 
        if(pNext != nullptr && pNext->m_nValue == pNode->m_nValue)
            needDelete = true;//那么[当前结点]是要删除的 
        //如果探测结果表明[当前结点]不需要删除
        if(!needDelete) {
            //那么双指针向后走一步 
            pPreNode = pNode;
            pNode = pNode->m_pNext;
        } else {//如果探测结果表明[当前结点]需要被删除,这时要向后找到下一类结点 
            int value = pNode->m_nValue;//记录要删除的这一串结点的共同值 
            ListNode* pToBeDel = pNode;//要被删除的结点从[当前结点]开始
            //往后走,只要没到结尾,而且值和要删除的结点一致 
            while(pToBeDel != nullptr && pToBeDel->m_nValue == value) {
                pNext = pToBeDel->m_pNext;//先获取下一结点,防止后续链表丢失 
                delete pToBeDel;//删除当前要删除的结点 
                pToBeDel = nullptr;
                pToBeDel = pNext;//要删除的结点再指向原下一结点 
            }
            //至此,这一串结点已经删除结束 
            if(pPreNode == nullptr)//如果前一结点为空,即不存在前置结点 
                *pHead = pNext;//说明刚刚删了开头的一串,要把头结点指向新发现的这类结点的第一个 
            else//否则,删除的不是开头的一串 
                pPreNode->m_pNext = pNext;//把前置结点的next指向新发现的结点,维持链表完整 
            pNode = pNext;//将[当前结点]指向新发现的结点 
        }
    }
}

猜你喜欢

转载自blog.csdn.net/SHU15121856/article/details/82423334
今日推荐