O(1)時間內刪除指定鏈表結點


題目

給定單鏈表頭指針和一個結點指針,定義一個函數在O(1)時間內刪除該結點。

分析

對於上圖實例鏈表(a)刪除指針p有兩種方式

  • 思路1:(b)找到前一個指針pre,賦值pre->next = p->next,刪掉p
  • 思路2:(c)目的是刪除p,但是不刪p,直接用p->next的值賦值給p,把p->next刪除掉(好處:不用遍歷找到p的前一個指針pre,O(1)時間內搞定)

於是,定位到思路2,但是思路2有兩個特例:

  1. 刪除的是尾指針,需要遍歷找到前一個指針
  2. 整個鏈表就一個結點(屬於刪尾指針,但沒法找到前面的指針,需要開小灶單獨處理)

大體算法思路

待刪指針不是尾指針:
      待刪指針的值用待刪指針的下一個指針的值覆蓋
      刪掉待刪指針的下一個指針
待刪指針是尾指針:
      待刪指針同時是頭指針:
            刪掉頭指針
     待刪指針不是頭指針
            找到待刪指針的前一個指針
            刪掉待刪指針,前一個指針的next賦值為空

參考代碼

bool deleteNode(ListNode *&head, ListNode *p)
{
    if(!p || !head)
        return false;
    if(p->m_pNext != NULL)   //不是尾指針
    {
        ListNode *del = p->m_pNext;
        p->m_nValue = del->m_nValue;
        p->m_pNext = del->m_pNext;
        delete del;
        del = NULL;
    }
    else if(head == p)      //是尾指針,同時只有一個結點
    {
        delete p;
        head = NULL;
    }
    else                     //是尾指針,同時有多個結點
    {
        ListNode *tmp = NULL, *pre = head;
        while(pre->m_pNext != p)
        {
            pre = pre->m_pNext;
        }
        delete p;
        p = NULL;
        pre->m_pNext = NULL;
    }
    return true;
}

完整代碼1

#include <iostream>
using namespace std;

struct ListNode
{
    int m_nValue;
    ListNode* m_pNext;
};

bool deleteNode(ListNode *&head, ListNode *p)
{
    if(!p || !head)
        return false;
    if(p->m_pNext != NULL)
    {
        ListNode *del = p->m_pNext;
        p->m_nValue = del->m_nValue;
        p->m_pNext = del->m_pNext;
        delete del;
        del = NULL;
    }
    else if(head == p)
    {
        delete p;
        head = NULL;
    }
    else
    {
        ListNode *tmp = NULL, *pre = head;
        while(pre->m_pNext != p)
        {
            pre = pre->m_pNext;
        }
        delete p;
        p = NULL;
        pre->m_pNext = NULL;
    }
    return true;
}
void createList(ListNode *&head)
{
    head = new(ListNode);
    head->m_nValue = 1;
    head->m_pNext = NULL;

    ListNode *p2 = new(ListNode);
    p2->m_nValue = 2;
    p2->m_pNext = NULL;
    head->m_pNext = p2;

    ListNode *p3 = new(ListNode);
    p3->m_nValue = 3;
    p3->m_pNext = NULL;
    p2->m_pNext = p3;

    ListNode *p4 = new(ListNode);
    p4->m_nValue = 4;
    p4->m_pNext = NULL;
    p3->m_pNext = p4;
}

void deleteList(ListNode *p)
{
    ListNode *next = NULL;
    while(p != NULL)
    {
        cout << p->m_nValue << endl;
        next = p->m_pNext;
        delete p;
        p = NULL;
        p = next;
    }
}

int main()
{
    ListNode *head = NULL;
    createList(head);
    ListNode *p = head->m_pNext->m_pNext->m_pNext;
    deleteNode(head, p);
    deleteList(head);
}
    
View Code

完整代碼2

#include <iostream>
using namespace std;

struct ListNode
{
    int m_nValue;
    ListNode* m_pNext;
};

bool deleteNode(ListNode **head, ListNode *p)
{
    if(!p || !head)
        return false;
    if(p->m_pNext != NULL)
    {
        ListNode *del = p->m_pNext;
        p->m_nValue = del->m_nValue;
        p->m_pNext = del->m_pNext;
        delete del;
        del = NULL;
    }
    else if(*head == p)
    {
        delete p;
        *head = NULL;
    }
    else
    {
        ListNode *tmp = NULL, *pre = *head;
        while(pre->m_pNext != p)
        {
            pre = pre->m_pNext;
        }
        delete p;
        p = NULL;
        pre->m_pNext = NULL;
    }
    return true;
}
void createList(ListNode *&head)
{
    head = new(ListNode);
    head->m_nValue = 1;
    head->m_pNext = NULL;

    ListNode *p2 = new(ListNode);
    p2->m_nValue = 2;
    p2->m_pNext = NULL;
    head->m_pNext = p2;

    ListNode *p3 = new(ListNode);
    p3->m_nValue = 3;
    p3->m_pNext = NULL;
    p2->m_pNext = p3;

    ListNode *p4 = new(ListNode);
    p4->m_nValue = 4;
    p4->m_pNext = NULL;
    p3->m_pNext = p4;
}

void deleteList(ListNode *p)
{
    ListNode *next = NULL;
    while(p != NULL)
    {
        cout << p->m_nValue << endl;
        next = p->m_pNext;
        delete p;
        p = NULL;
        p = next;
    }
}

int main()
{
    ListNode *head = NULL;
    createList(head);
    ListNode *p = head->m_pNext->m_pNext;
    deleteNode(&head, p);
    deleteList(head);
}
    
View Code

分析

刪除非尾結點時間復雜讀為O(1),刪除尾結點的時間復雜讀為O(n), 平均時間復雜度為[(n-1)*O(1) + O(N)] / N = O(1)

還有刪除函數並不能處理待刪結點就是該鏈表中的指針,因此需要人為調用時控制,如果得驗證的話,那就沒必要做這些處理了,直接O(N)

技術細節——傳值操作

#include <iostream>
using namespace std;

struct ListNode
{
    int m_nValue;
    ListNode* m_pNext;
};

void createList(ListNode *head)
{
    head = new(ListNode);
    head->m_nValue = 1;
    head->m_pNext = NULL;
}
void deleteList(ListNode *p)
{
    ListNode *next = NULL;
    while(p != NULL)
    {
        cout << p->m_nValue << endl;
        next = p->m_pNext;
        delete p;
        p = NULL;
        p = next;
    }
}

int main()
{
    ListNode *head = NULL;
    createList(head);
    cout << head << endl;
    deleteList(head);
}
    

主函數中的指針head為傳值調用,傳到函數並沒有改變主函數中的值,圖示

改進的措施就是引用傳值,直接操縱原指針。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM