前提
鏈表是多個不一定連續的內存塊(節點),通過節點保存的後置指針或前置指針串聯起來的一種數據結構;
鏈表不支持隨機訪問;
下面的反轉鏈表沒有特別提示的都是帶頭鏈表(引入了哨兵的鏈表),用java實現,節點類如下:
/**
* @Author Haoqi
* @Description 鏈表節點
**/
Class Node{
int data;
Node next;
/**
* 構造哨兵節點
**/
public Node() {
this.data = -1;
this.next = null;
}
//其他構造方法
//...
}
兩種實現
原地反轉
通過指針的變化,在鏈表自身進行反轉,不會產生另外一個新鏈表;
public static Node reverseLinkList(Node head){
if(head.next == null){
return head;
}
Node prev = head.next;
Node pcur = prev.next;
while(pcur != null){
prev.next = pcur.next;
pcur.next = head.next;
head.next = pcur;
pcur = prev.next;
}
return head;
}
- head節點是哨兵節點,不存數據只是,只是爲了簡化代碼;
- 第一個判斷看鏈表是否爲空鏈表,即除了哨兵沒有其他數據節點;
- 實現需要兩個指針,一個前置指針 prev ,一個移動指針pcur;
- 循環結束條件是移動指針爲null;
- 注意指針操作順序防止指針丟失,這裏可以逐步畫圖演示,輔助理解;
- pcur指針指向的是下次循環結束後的第一個數據節點 head.next = pcur;
- 最後pcur向後移動,但每次循環開始結束prev一直是pcur的前置節點;
- 時間複雜度O(n)
頭插法反轉
顧名思義,遍歷舊鏈表,反覆向新鏈表的第一個節點位置插入,產生的新鏈表就是舊鏈表的反轉;
public static Node reverseLinkList(Node head){
if(head.next == null){
return head;
}
Node newHead = new Node();
Node pcur = head.next;
Node curNextTmp = null;
while(pcur != null){
curNextTmp = pcur.next;
pcur.next = newHead.next;
newHead.next = pcur;
pcur = curNextTmp;
}
return newHead;
}
- head節點是哨兵節點,不存數據只是,只是爲了簡化代碼;
- 第一個判斷看鏈表是否爲空鏈表,即除了哨兵沒有其他數據節點;
- 實現需要新建一個帶頭空鏈表newHead,一個移動指針pcur和一個緩存curNextTmp;
- 循環結束條件是移動指針爲null;
- 每次循環,先將pcur的後續節點緩存起來,然後再向新鏈表第一個數據節點處插入pcur(頭插),最後將pcur移到緩存的後續節點;
- 時間複雜度爲O(n)
熄燈
怎麼寫出正確的鏈表?畫圖理解記憶,再多默寫幾次就行。