1. 程式人生 > >反轉連結串列的演算法實現

反轉連結串列的演算法實現

題目:定義一個函式,輸入一個連結串列的頭結點,反轉該連結串列並輸出反轉後連結串列的頭結點。 下面給出了連結串列結點的定義:

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};

分析:   連結串列前後元素的關聯就是通過指標實現的,每個連結串列都有一個next指標指向下一個結點,末尾的節點的next域則置NULL;   反轉連結串列就是要求修改指標的指向。下面的圖就是反轉前和反轉後的效果。 反轉前: 在這裡插入圖片描述 反轉後: 在這裡插入圖片描述

下面來談談如何對連結串列進行反轉。 在這裡插入圖片描述 假設我們現在正在對結點v進行反轉操作,即原來結點u的next域指向v(圖中已經調整完畢,現在指向前一個結點),v的next域指向w。現在要做的是將v的next域指向u。從圖中我們可以看出,當把v的next指標指向u的同時,原先指向的w就已經無法被正常的訪問到了,為了避免“斷鏈”,我們必須在指標更改指向之前,儲存修改結點的下一結點。同時我們也必須儲存上一個結點,因為next域即將修改指向該結點。因此定義三個指標,分別指向當前遍歷的結點,前一個結點和後一個結點。 演算法實現如下:

ListNode* ReverseList(ListNode* pHead)
{
    ListNode* pReversedHead = NULL;
    ListNode* pNode = pHead;
    ListNode* pPrev = NULL;
    while(pNode != NULL)
    {
        ListNode* pNext = pNode->m_pNext;

        if(pNext == NULL)
            pReversedHead = pNode;

        pNode->m_pNext = pPrev;

        pPrev = pNode;
        pNode = pNext;
    }

    return pReversedHead;
}

當然,上面的原始碼中用到了四個指標,看完原始碼就會發現和上面分析的原理並沒有相悖。或者下面這樣也是可以的,兩者的思路一致,沒有差別。只不過下面的程式碼必須注意一點,跳出while迴圈的時候,最後一個結點的next域別忘記指向前一個結點,否則就會導致“斷鏈”。

ListNode* ReverseList(ListNode* pHead) {
        ListNode *root=pHead; 
        ListNode *pre=NULL;  
        ListNode *next=NULL;
        if(pHead==NULL) return NULL; 
    while(root->next){  
        next=root->next;   
        root->next=pre;      
        pre=root;       
        root=next;     
    }    
        root->next=pre; 
        return root; 
    }