單鏈表查找倒數第k個節點


題目:輸入一個單向鏈表,輸出該鏈表中倒數第k個結點。鏈表的倒數第0個結點為鏈表的尾指針。

分析:為了得到倒數第k個結點,很自然的想法是先走到鏈表的尾端,再從尾端回溯k步。可是輸入的是單向鏈表,只有從前往后的指針而沒有從后往前的指針。因此我們需要打開我們的思路。既然不能從尾結點開始遍歷這個鏈表,我們還是把思路回到頭結點上來。假設整個鏈表有n個結點,那么倒數第k個結點是從頭結點開始的第n-k-1個結點(從0開始計數)。如果我們能夠得到鏈表中結點的個數n,那我們只要從頭結點開始往后走n-k-1步就可以了。如何得到結點數n?這個不難,只需要從頭開始遍歷鏈表,每經過一個結點,計數器加一就行了。這種思路的時間復雜度是O(n),但需要遍歷鏈表兩次。第一次得到鏈表中結點個數n,第二次得到從頭結點開始的第n­-k-1個結點即倒數第k個結點。如 果鏈表的結點數不多,這是一種很好的方法。但如果輸入的鏈表的結點個數很多,有可能不能一次性把整個鏈表都從硬盤讀入物理內存,那么遍歷兩遍意味着一個結 點需要兩次從硬盤讀入到物理內存。我們知道把數據從硬盤讀入到內存是非常耗時間的操作。我們能不能把鏈表遍歷的次數減少到1?如果可以,將能有效地提高代碼執行的時間效率。如果我們在遍歷時維持兩個指針,第一個指針從鏈表的頭指針開始遍歷,在第k-1步之前,第二個指針保持不動;在第k-1步開始,第二個指針也開始從鏈表的頭指針開始遍歷。由於兩個指針的距離保持在k-1,當第一個(走在前面的)指針到達鏈表的尾結點時,第二個指針(走在后面的)指針正好是倒數第k個結點。這種思路只需要遍歷鏈表一次。對於很長的鏈表,只需要把每個結點從硬盤導入到內存一次。因此這一方法的時間效率前面的方法要高。

 

#include <iostream>
#include <map>
using namespace std;
typedef struct ListNode{
    int m_nkey;
    ListNode *m_pnext;
} ListNode,*Node;
int main()
{
    int n,k;
    cout<<"The length of the list: "<<endl;
    cin>>n;
    cout<<"Which one to select(from tail): "<<endl;
    cin>>k;
    Node head,tmp,last;
    for(int i=n;i>=1;i--)
    {
        tmp=new ListNode();
        tmp->m_nkey=i;
        if(i==n)
        head=tmp;
        else
        last->m_pnext=tmp;
    tmp->m_pnext=NULL;
    last=tmp;
    }
    Node p=head;
    Node q=head;
    int i=1;
    while(p!=NULL)
    {
        if(i<=k)
        {
            i++;
            p=p->m_pnext;
        }
        else
        {
            p=p->m_pnext;
            q=q->m_pnext;
        }
    }
    cout<<"The data is: "<<q->m_nkey<<endl;
}

 

  

 


免責聲明!

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



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