在很多家公司面試,也包括在攜程,大多都會被問到一些演算法的問題,其中機票事業部的面試,基本上算是演算法問題的重災區,沒辦法,有幾個領導喜歡
用資料結構來考人家,其中包括一些常見資料結構的複雜度以及手寫一些演算法,比如快排,單連結串列等等,前幾天我一個推薦過來的朋友膝蓋就被中了一箭。
題目就不方便具體說了,第一小問就是用非遞迴來構建一個單連結串列,我們知道構建單連結串列可以說是學資料結構的基本功,一說到用鏈式結構,它跟遞迴
又有了千絲萬縷的聯絡,很多鏈式的問題,我們用遞迴就可以輕輕鬆鬆的解決,幾乎不需要動一下腦子,但是如果用非遞迴的話,那就稍微比遞迴要複雜一點
了,起碼會多考一個引用型別記憶體分配的問題。
後來QQ上我就用遞迴和非遞迴的形式構建單連結串列回覆了他,先給了一個遞迴的版本,這個沒問題,可以消化,然後給了一個非遞迴的版本,看了之後就扛
不住了。
一:遞迴版本
1 class LinkList 2 { 3 public class LinkNode 4 { 5 public int data; 6 7 public LinkNode next; 8 } 9 10 private LinkNode head; 11 12 public void Add(int data) 13 { 14 if (head == null) 15 { 16 head = new LinkNode() { data = data }; 17 } 18 else 19 { 20 Add(head, data); 21 } 22 } 23 24 public void Add(LinkNode node, int data) 25 { 26 if (node.next == null) 27 { 28 node.next = new LinkNode() { data = data }; 29 return; 30 } 31 32 Add(node.next, data); 33 } 34 }
二:非遞迴版本
1 class LinkList 2 { 3 public class LinkNode 4 { 5 public int data; 6 7 public LinkNode next; 8 } 9 10 private LinkNode head; 11 12 public void Add(int data) 13 { 14 LinkNode node = new LinkNode() { data = data }; 15 16 if (head == null) 17 { 18 head = node; 19 } 20 else 21 { 22 LinkNode temp = head; 23 24 while (temp.next != null) 25 { 26 temp = temp.next; 27 } 28 29 temp.next = node; 30 } 31 } 32 }
這個非遞迴不理解的地方在於臨時變數temp,提出的問題就是為什麼:“temp.next=node” 之後,head的值發生了改變?我想之所以不能理解,絕逼是對
引用型別的記憶體分配不瞭解,而這個非遞迴版本恰恰就是用引用型別這個記憶體分配技巧來實現 ”非遞迴構建單連結串列“。。。為了不讓別人踩上這個坑,我還是大
概說一下流程,大概是這樣的,當我們在new一個引用型別的時候,CLR就要計算例項欄位和所有基類上的例項欄位的大小,然後再在堆上分配合理的記憶體塊,
最後把堆上的記憶體塊的首地址儲存在棧上面。
為了方便理解,現在假如LinkList裡面有三個結點:instance1 -> instance2 -> instance3,
第一句:
1 LinkNode temp = head;
這個句子不難理解吧,把head的地址賦給temp,那麼棧上temp的地址也就是head的地址,head的地址就是指向instacnce1記憶體塊地址。
第二句: 從這句while中可以看到,一直在找instance的next,可以看出之後把instance2的記憶體地址給了temp,再next之後就把instance3的記憶體地址給
了temp,然後就發現instance3的next為null,然後就跳出迴圈。
1 while (temp.next != null) 2 { 3 temp = temp.next; 4 }
第三句:從上一句可以看到,instance3的next已經為null了,這時候就把新構建的結點:LinkNode node = new LinkNode() { data = data };賦
給temp的next指標上來繼續構建連結串列。
1 temp.next = node;
可以看到這時候instance4就構造到了instance3之後,同時temp.next已經是儲存instance4的記憶體地址,這一些操作對head來說都是透明的,它也不管
後面怎麼操作,當你遍歷head的時候會驚奇的發現居然我的連結串列中多了一個instance4,這個也就是朋友疑惑的地方,如果看到這個記憶體分配圖的話,
也許會豁然開朗,當然這篇博文沒什麼技術含量,也是自己一時有感而發。