面試題16:反轉鏈表


題目:定義一個函數,輸入一個鏈表的頭結點,反轉該鏈表並輸出反轉后鏈表的頭結點。

 假設有鏈表A->B->C->D->E->F->G。在反轉鏈表過程中的某一階段,其鏈表指針指向為:A<-B<-C<-D  E->F->G。也就是說在結點D之前的所有結點都已經反轉,而結點D后面的結點E開始的所有結點都沒有反轉。這樣D跟E之間存在了斷裂。我們如果要實現鏈表的反轉,會有以下幾個重要步驟:

  1. D->E變為D->C,指針反轉
  2. 指針往后移動一個,操作下一個結點E
  3. 結合1.2我們發現需要操作3個指針,分別是C,D,E。

因此可以考慮存儲C/D/E三個結點的指針,通過這三個結點的指針實現反轉。

代碼實例:

View Code
#include<iostream>
#include<stdlib.h>
#include<stack>
using namespace std;

//鏈表結構
struct ListNode
{
    int m_nValue;
    ListNode* m_pNext;
};

//創建一個鏈表結點
ListNode* CreateListNode(int value)
{
    ListNode *pNode=new ListNode();
    pNode->m_nValue=value;
    pNode->m_pNext=NULL;
    return pNode;

}

//遍歷鏈表中的所有結點
void PrintList(ListNode* pHead)
{
    ListNode *pNode=pHead;
    while(pNode!=NULL)
    {
        cout<<pNode->m_nValue<<" ";
        pNode=pNode->m_pNext;
    }
    cout<<endl;
}

//往鏈表末尾添加結點
/*
注意這里pHead是一個指向指針的指針,在主函數中一般傳遞的是引用。
因為如果要為鏈表添加結點,那么就會修改鏈表結構,所以必須傳遞引用才能夠保存修改后的結構。
*/
void AddToTail(ListNode** pHead,int value)
{
    ListNode* pNew=new ListNode();//新插入的結點
    pNew->m_nValue=value;
    pNew->m_pNext=NULL;

    if(*pHead==NULL)//空鏈表
    {
        *pHead=pNew;
    }
    else
    {
        ListNode* pNode=*pHead;
        while(pNode->m_pNext!=NULL)
            pNode=pNode->m_pNext;
        pNode->m_pNext=pNew;
    }

}

ListNode* ReverseList(ListNode* pHead)
{
    ListNode* pNode=pHead;//當前結點
    ListNode* pPrev=NULL;//當前結點的前一個結點
    ListNode* pReversedHead=NULL;//反轉鏈表頭結點
    while(pNode!=NULL)
    {
        ListNode* pNext=pNode->m_pNext;
        if(pNext==NULL)//如果當前結點的下一個結點為空,那么反轉鏈表的頭結點就是當前結點。
            pReversedHead=pNode;

        pNode->m_pNext=pPrev;//當前結點指向前一個結點

        pPrev=pNode;//pPrev和pNode往前移動。
        pNode=pNext;//這里要使用前面保存下來的pNext,不能使用pNode->m_pNext
    }
    return pReversedHead;//返回反轉鏈表頭指針。
}

void main()
{
    //創建結點
    ListNode* pNode1=CreateListNode(1);//創建一個結點
    PrintList(pNode1);//打印
    //往鏈表中添加新結點
    AddToTail(&pNode1,2);//為鏈表添加一個結點
    AddToTail(&pNode1,3);//為鏈表添加一個結點
    AddToTail(&pNode1,4);//為鏈表添加一個結點
    AddToTail(&pNode1,5);//為鏈表添加一個結點
    AddToTail(&pNode1,6);//為鏈表添加一個結點
    AddToTail(&pNode1,7);//為鏈表添加一個結點
    //打印鏈表
    PrintList(pNode1);//打印
    //反轉鏈表
    ListNode* pReversedHead=ReverseList(pNode1);
    PrintList(pReversedHead);//打印

    system("pause");

}

運行結果:

1
1 2 3 4 5 6 7
7 6 5 4 3 2 1

ps:2012-5-3

發現有一種更加簡潔的寫法,就是不需要pReversedHead指針,從上述程序我們可以看出來pReversedHead指針只是單純的用來保存反轉鏈表的頭指針,但是pPrev和pNode指針其實就包含反轉鏈表的頭指針,因此我們沒有必要單獨定義一個頭指針來保存。修改后的函數如下所示:

View Code
ListNode* ReverseList2(ListNode* pHead)
{
    ListNode* pNode=pHead;//當前結點
    ListNode* pPrev=NULL;//當前結點的前一個結點
    while(pNode!=NULL)
    {
        ListNode* pNext=pNode->m_pNext;
        pNode->m_pNext=pPrev;//當前結點指向前一個結點

        pPrev=pNode;//pPrev和pNode往前移動。
        pNode=pNext;//這里要使用前面保存下來的pNext,不能使用pNode->m_pNext
    }
    return pPrev;//返回反轉鏈表頭指針。
}

 

 


免責聲明!

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



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