鍊錶翻轉,簡單地理解,就是將鍊錶的頭部結點變為鍊錶的尾部結點,與此同時將原鍊錶的尾部結點變成頭部結點。如下圖所示:
圖 1 鍊錶翻轉示意圖
將鍊錶進行翻轉的方法有多種,本節給大家介紹兩種實現方法。
實現鍊錶翻轉最直接的方法就是:從鍊錶的頭部開始遍歷每個結點,改變每個結點的指向,即將原本指向下乙個結點的指標改為指向上乙個結點。
唯一比較特殊的是,鍊錶中的首元結點(第乙個結點)前面沒有結點,所以在改變其指標指向的時候,要將其指標指向 null。
具體實現過程為:
首先設定乙個新的鍊錶,用於接收舊煉表上的結點,該新鍊錶初始狀態為乙個空鍊錶,如下圖所示:
圖 2 鍊錶翻轉過程一
遍歷原鍊錶,將結點依次插入到新鍊錶的頭部。要完成這一步操作,我們需要新新增兩個指標(分別命名為 p 和 temp):
新新增指標 p 和 temp 後的鍊錶,如下圖所示:
圖 3 鍊錶翻轉過程二
以上的準備工作完成,鍊錶的翻轉就可以開始了。在遍歷原鍊錶的過程中,對每個結點都做如下操作:
注意:第一步必須要在第四步的前面,否則會導致最終temp指向 null 的next,發生錯誤。遍歷每個結點的過程示意圖如下:
翻轉結點 1 ,則圖 3 經過以上 4 步調整後,變為:
圖 4 翻轉結點 1
翻轉結點 2,則上圖經過 4 步調整後,變為下圖:
圖 5 翻轉結點 2
翻轉結點 3 時,則上圖經過 4 步調整後,變為下圖:
圖 6 翻轉結點 3
當翻轉完最後乙個結點 3 之後,由於指標 p 指向的為 null ,說明沒有結點可以翻轉,即遍歷結束。(指標 p 為null ,為遍歷結束的判斷條件)。
link *reverselink(link *h)另一種方法較前一種比較複雜,需要使用到遞迴的思想。// 建立指標 p 作為遍歷鍊錶的指標
link *p =h;
// 建立乙個新的鍊錶,用於儲存翻轉鍊錶,只不過該鍊錶初始狀態為null
link *newh =null;
// 遍歷指標 p 為 null 作為遍歷結束的標誌
while(p !=null)
return
newh;
}
方法一是依次遍歷鍊錶,更改每個結點的指向,最後乙個結點為翻轉鍊錶的頭部結點。而方法二則完全倒過來,其實現過程為:先通過遞迴的思維找到鍊錶的頭部,然後再改變每個結點的指向,最終到達鍊錶翻轉的目的。
方法二的**實現函式為:
//**執行過程分析:鍊錶翻轉的函式
link *reverselist(link *h)
// 遞迴查詢新鍊錶的頭,找到用賦值給 newh
link *newh = reverselist(h->next);
// 遞迴完成後,h 初始狀態為 newh 的上乙個結點。
// 在一步步彈棧的過程中,始終另 h 指向的結點作為新鍊錶的最後乙個結點
h->next->next = h;
// h->next = null;
// 返回新鍊錶所指頭部的指標。
return
newh;
}
4-6行:對於給定的指標 h ,首先判斷指標 h 是否存在,如果指標 h 不存在,或者指標 h 只含有乙個結點,則直接返回,即指標 h 不需要翻轉;
第 8 行:函式體內呼叫自身,是典型的遞迴。通過不斷查詢指標 h 所指結點的下乙個結點,最終會找到鍊錶的最後乙個結點作為函式的返回值,而此結點恰恰就是翻轉後鍊錶的首元結點(第乙個結點),所以我們用乙個新指標 newh 來充當新鍊錶的頭指標。
當通過遞迴找到對應的 newh 結點時,相應地,引數指標 h 也被遞迴至 newh 所指結點的上一結點處,如下圖所示:
圖 7 遞迴結束時的示意圖
注意:頭指標 h 和引數指標 h 完全不是一碼事,作用域不同:引數 h 只在函式體內有效,而頭指標 h 為主函式中宣告。第 11行到最後:此部分**為指標 h 逐層返回時才會執行的**,在逐層返回的過程中,通過不斷地將h所指結點賦值給 h->next->next,並且每次賦值結束後,都取消 h 所指結點的指向,最終達到翻轉鍊錶的目的。
自圖 7 開始,在指標 h 第一次返回時,此部分的**執行示意圖為:
指標 h 再次返回時,此部分的**執行示意圖為:
最終完成了鍊錶的翻轉,函式返回新鍊錶的頭指標 newh 。
#include #includetypedef
struct
link
link;
link *initlink();
// 建立首元結點
link *head=(link*)malloc(sizeof
(link));
head->count = element[0
];
// for迴圈中需要乙個指標temp,從頭結點開始依次鏈結新建立的結點
link *temp = head;
// for迴圈逐個建立鍊錶,並用temp兩兩鏈結
for (int i=1; i<3; i++)
return
head;
}//
方法一實現鍊錶翻轉
link *reverselink(link *h)
// 建立指標 p 作為遍歷鍊錶的指標
link *p =h;
// 建立乙個新的鍊錶,用於儲存翻轉鍊錶,只不過該鍊錶初始狀態為null
link *newh =null;
// 遍歷指標 p 為 null 作為遍歷結束的標誌
while(p !=null)
return
newh;
}//
方法二實現鍊錶翻轉
link *reverselist(link *h)
// 遞迴查詢新鍊錶的頭,找到用賦值給 newh
link *newh = reverselist(h->next);
// 遞迴完成後,h 初始狀態為 newh 的上乙個結點。
// 在一步步彈棧的過程中,始終另 h 指向的結點作為新鍊錶的最後乙個結點
h->next->next = h;
// h->next = null;
// 返回新鍊錶所指頭部的指標。
return
newh;}//
遍歷鍊錶的輸出函式
void display(link *h)
printf("\n
");}int
main ()
執行結果:
123321
123
資料結構 鍊錶的逆置
將乙個鍊錶進行逆置 如 10 20 30 40 逆置後40 30 20 10 分析 方法一 新建鍊錶 遍歷舊鍊錶,將舊鍊錶的結點依此頭插到新鍊錶中。上 include include typedef struct node node 建立結點 node buynode int data 用建立新鍊錶...
資料結構實驗之鍊表三 鍊錶的逆置
time limit 1000ms memory limit 65536k 輸入多個整數,以 1作為結束標誌,順序建立乙個帶頭結點的單鏈表,之後對該單鏈表的資料進行逆置,並輸出逆置後的單鏈表資料。輸入多個整數,以 1作為結束標誌。輸出逆置後的單鏈表資料。12 56 4 6 55 15 33 62 1...
資料結構實驗之鍊表三 鍊錶的逆置
資料結構實驗之鍊表三 鍊錶的逆置 輸入多個整數,以 1作為結束標誌,順序建立乙個帶頭結點的單鏈表,之後對該單鏈表的資料進行逆置,並輸出逆置後的單鏈表資料。輸入多個整數,以 1作為結束標誌。輸出逆置後的單鏈表資料。12 56 4 6 55 15 33 62 1 62 33 15 55 6 4 56 1...