為什么面試常考鏈表反轉
鏈表是常用的數據結構,同時也是面試常考點,鏈表為什么常考,因為鏈表手寫時,大多都會有許多坑,比如在添加節點時因為順序不對的話會讓引用指向自己,因此會導致內存泄漏等問題,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}}}}