為什麼面試常考連結串列反轉
連結串列是常用的資料結構,同時也是面試常考點,連結串列為什麼常考,因為連結串列手寫時,大多都會有許多坑,比如在新增節點時因為順序不對的話會讓引用指向自己,因此會導致記憶體洩漏等問題,Java會有JVM管理記憶體,可能不會引起太大問題,如果是c、c++、c#,這些語言都需要手動釋放記憶體,如果操作不當後果不堪設想。其原因就是程式設計師對(引用)指標的理解出現偏差。
如果不瞭解Java引用可以檢視這篇部落格:
怎樣實現連結串列反轉
翻轉連結串列實現如下:
public class Link {
Node head;
public void reverse() {
if (head.isEmpty() || head.next.isEmpty()) return;
Node cur = head.next;
Node pre = head;
while (cur!=null) {
Node tmp = cur.next;
cur.next = pre; //變成了 cur-》pre-》源cur.next節點
head.next = tmp;
//2->1->3 c:3 p:2 3->2->4(1節點直接被4覆蓋),需要修改
pre = cur;
cur = tmp;
tmp = null; //垃圾回收
}
head = pre;
}
public boolean isEmpty() {
return head == null;
}
}
class Node {
int val;
Node next;
public Node(int val) {
this.val = val;
next = null;
}
public boolean isEmpty() {
return this == null;
}
@Override
public String toString() {
return "Node{" +
"val=" + val +
", next=" + next +
'}';
}
}
分析思路:
一般嘗試,如果直接while讓cur.next=cur;在cur.next=cur之前拿到cur.next的下一個節點,會出現子級指向自己的死環,這是不可取的。
換一個方法,如果多新增一個是否會有幫助,新增一個pre=head引用,讓cur移動一個單位,現在cur從head.next的位置,讓cur的下一個位置
儲存pre引用的地址,在cur的下一位置重新指向前事先讓pre指向cur.next節點
原始碼如下:
while ()
{
pre.next = cur.next;
cur.next = pre; //變成了 cur-》pre-》源cur.next節點
Node tmp = pre; //2->1->3 c:3 p:2 3->2->4(1節點直接被4覆蓋),需要修改
pre = cur;
cur = tmp;
tmp = null; //垃圾回收
}
很明顯,原始碼中並沒有未排序的部分新增到連結串列尾部,而是直接放到了pre節點的後邊,造成了汙染資料的後果,經過修改後就是上面帶實現類原始碼。
如果不明白為什麼是head.next=tmp;假如有一個連結串列是1->2->3->4,第一次翻轉時候都是讓cur放到pre的前面,再把沒有排序的部分放到後邊,如果第二次在按照這個思路跑的話,就會變成3->2->4,就會把原來2後邊的1覆蓋了,這裡就有問題了,後邊的節點不應該放到2後邊,而是應該放到1,這個1正好是原來連結串列的head節點,所以每次新增的位置應該是head後邊。
最後結果
最後跑完的結果是:
DEBUG:
Node{val=4, next=Node{val=3, next=Node{val=2, next=Node{val=1, next=null}}}}