題目:給定乙個單向鍊錶,請設計乙個既節省時間又節省空間的演算法來找出該鍊錶中的倒數第m個元素。實現這個演算法。「倒數第m個元素」是這樣規定的:當m=0時,鍊錶的最後乙個元素(尾元素)將被返回。
分析:單鏈表是只能正向遍歷的,並不適合查詢倒數第m個元素,如果需要這類操作,在實際應用中也不會用到單鏈表(也許你會選擇雙向鍊錶)。這裡只是就題論題。
第乙個比較簡單的思路是按照正序遍歷鍊錶,然後針對遍歷的當前元素判斷其是否是倒數第m個元素(有點類似於二重迴圈)。偽**如下:
遍歷鍊錶,node表示當前鍊錶節點
判斷node是否是倒數第m各元素,如果是則直接返回,如果不是繼續迴圈
直到鍊錶結束
對於這個方法的複雜度,如果鍊錶的長度為n,則演算法的執行時間大約是o(mn)的。如果m、n都比較大這種方法是很不可取的。
會不會有更簡單的方法呢?如果我們知道鍊錶的長度n,查詢倒數第m個元素,也就是查詢正序的第(n - m)個元素(這裡的序號只是為了分析,可能跟題目不一定正確的符合)。那麼這樣來說就簡單很多。首先遍歷鍊錶得到鍊錶長度,然後重新遍歷一次,查詢正數第(n-m)個元素。時間複雜度大約是o(2n)。(這裡考慮下,如果能夠在一次遍歷內得到結果是不是更好的?)
我們還可以從另乙個角度分析下,既然單向鍊錶不能進行逆序查詢,我們是不是可以提供乙個輔助儲存空間,是的我們在遍歷到鍊錶結束的時候可以回溯到倒數第m個元素。比如用乙個支援隨機訪問的容器記錄鍊錶每乙個節點的位址。那麼這樣的就可以只遍歷一次鍊錶就能得到結果。時間複雜度大約是o(n),但是我們是用空間換取時間的,輔助儲存空間的大小由m決定,如果m過大也是不可取的。
我們考慮下是不是可以把上面的思路的空間複雜度也降下來。按照目前的思路,合理的選擇輔助儲存空間,可以使空間複雜度為o(m),比如你可以對鍊錶進行開窗處理(窗的大小為m),隨著遍歷的進行,當前節點總是窗的頭結點,窗中依次記錄當前節點之前的m個節點。這樣當我們遍歷到鍊錶尾的時候,窗的尾節點就是所求。
我們再深入一下,其實這個窗並沒有多大用處,這裡指的是中間的元素。是不是可以去掉呢?
既然我們只關心窗的頭結點和尾節點,那麼我們就簡單點用兩個指標記錄。那麼具體該如何處理呢?
假定頭結點指標為當前指標,尾節點指標為拖後指標。開始的時候當前指標和拖後指標初始化為鍊錶的頭結點,首先我們讓當前指標遍歷到第m個元素,拖後指標不變;然後同步更新當前指標和拖後指標;直到當前指標為鍊錶結尾。這樣我們就能保證當前指標和拖尾指標之間的距離是m。
經過這麼乙個思考過程,你可以開始寫**了。但是還是要注意倒數第m個元素究竟指的是那個元素,可以參考題目中的說明。另乙個問題是特殊情況,如果鍊錶長度n
具體**:
node* findmtolastnode(node* phead, int m)
else
}// 一起繼續遍歷到鍊錶尾部,
// 現在pfind和pcurrent之間間隔了m個元素,
// 所以,當pcurrent遍歷到尾部的時候,
// pfind就到了倒數第m個元素的位置上.
node* pfind = phead;
while (pcurrent)
return pfind;
}
注:鍊錶的節點定義,這裡不給出了。 求鍊錶的倒數第m個元素
習題3.5 求鍊錶的倒數第m個元素 20分 請設計時間和空間上都盡可能高效的演算法,在不改變鍊錶的前提下,求鏈式儲存的線性表的倒數第m 0 0 個元素。elementtype find list l,int m 其中list結構定義如下 typedef struct node ptrtonode s...
求鍊錶的倒數第m個元素
方法一 先遍歷一次鍊錶,得到長度n,在從頭遍歷找到第n m 1個元素。elementtype find list l,int m if m n m的位置不合法 int i 1 p l for i n m 1 i p p next return p data 方法二 定義兩個指標變數p1,p2,在初始...
求鍊錶的倒數第m個元素
請設計時間和空間上都盡可能高效的演算法,在不改變鍊錶的前提下,求鏈式儲存的線性表的倒數第m 0 個元素。函式介面定義 elementtype find list l,int m 其中list結構定義如下 typedef struct node ptrtonode struct node typede...