使用雙重指針實現鏈表結點的插入與刪除

單鏈表結點的插入和刪除是數據結構中很基本的操作。如果單鏈錶帶有頭結點,那麼可以把頭結點指針傳遞給插入和刪除函數;可如果對無頭結點的單鏈表進行上述操作,僅傳遞頭指針(指向第一個結點的指針),在插入或刪除操作改變鏈表頭指針時,將會有些問題。
下面我們通過一個實例說明這個問題。

//單鏈表結點定義
struct ListNode
{
    int val;
    ListNode* next;
    ListNode(int value):val(value), next(NULL){}
};

採用“尾插法”向鏈表中插入結點,如果用以下代碼實現:

//insert.cpp version_1
void add2Tail(ListNode* pHead, int value)
{
    ListNode* pNew = new ListNode(value);
    if(!pHead) pHead = pNew;    //?
    else
    {
        ListNode* pNode = pHead;
        while(pNode->next) pNode = pNode->next;
        pNode->next = pNew;
    }   
}

上述代碼中,給add2Tail函數傳遞的是指向鏈表第一個結點的指針。可是這段代碼第四行有個很嚴重的問題,由於當原鏈表爲空,插入新結點時會改變“頭指針”pHead,但這種改變僅僅改動的是函數內部的局部變臉pHead,原鏈表“頭指針”(實參)實際上仍爲NULL。具體可參照下面的圖示:

鏈表指針
tips:上圖中,當函數形參爲指向鏈表第一個結點的指針時,”傳值“方式傳遞的是地址100;而形參如果爲指向頭指針的指針,傳遞的是地址200。

因此我們要對這段代碼做一些改動,給add2Tail傳遞指向“頭指針”的指針,這樣便可達到當pHead==NULL時,插入新結點後也可改動外部的pHead。代碼如下:

//insert.cpp version_2
void add2Tail(ListNode** pHead, int value)
{
    ListNode* pNew = new ListNode(value);
    if(!*pHead) *pHead = pNew;    //原鏈表爲NULL
    else
    {
        ListNode* pNode = *pHead;
        while(pNode->next) pNode = pNode->next;
        pNode->next = pNew;
    }   
}

同理,刪除單鏈表中第一個含有某特定值的結點時,如果第一個結點就是待刪除結點的話,這將改變頭指針,因此也要給刪除函數傳遞指向頭指針的指針,代碼如下:

void removeNode(ListNode** pHead, int value)
{
    if(!pHead || !*pHead) return;
    ListNode *p2BeRemoved = NULL;
    if((*pHead)->val == value)    //第一個結點爲待刪除對象
    {
        p2BeRemoved = *pHead;
        *pHead = (*pHead)->next;
    }
    else    
    {
        ListNode* pNode = *pHead;
        while(pNode->next && pNode->next->val != value) pNode = pNode->next;

        if(pNode->next && pNode->next->val == value)
        {
            p2BeRemoved = pNode->next;
            pNode->next = pNode->next->next;
        }
    }

    if(p2BeRemoved)
    {
        delete p2BeRemoved;    
        p2BeRemoved = NULL;   //刪除指針後,最後將其賦與NULL值,防止野指針
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章