題目:輸入兩個遞增排序的鏈表,合併這兩個鏈表並使新鏈表中的結點仍然是按照遞增排序的。例如輸入圖中的鏈表1和鏈表2,則合併以後的升序鏈表3所示。面試
這是一個常常被各公司採用的面試題。在面試過程當中,咱們發現應聘者最 容易犯兩個錯誤:一是在寫代碼以前沒有對合並的過程想清楚,最終合併出來的鏈表要麼中間斷開要麼並無遞增排序;二是代碼的魯棒性方面存在問題,程序一旦 有特殊的輸入(如空鏈表)就會崩潰。接下來分析如何解決這個問題。函數
首先分析合併兩個鏈表的過程。咱們的分析從合併兩個鏈表的頭結點開始。鏈表1的頭結點的值小於鏈表2的頭結點的值,所以鏈表1的頭結點將是合併後鏈表的頭結點,如圖所示:.net
咱們繼續合併兩個鏈表中剩餘的結點。在兩個鏈表中剩下的結點依然是排 序的,所以合併這兩個鏈表的步驟和前面的步驟是同樣的。咱們仍是比較兩個頭結點的值。此時鏈表2的頭結點的值小於鏈表1的頭結點的值,所以鏈表2的頭結點 的值將是合併剩餘結點獲得的鏈表的頭結點。咱們把這個結點和前面合併鏈表時獲得的鏈表的尾節點連接起來,如圖所示。指針
當咱們獲得兩個鏈表中值較小的頭結點並把它連接到已經合併的鏈表以後,兩個鏈表剩餘的結點依然是排序的,所以合併的步驟和以前的步驟是同樣的。這就是典型的遞歸的過程,咱們可疑定義遞歸函數完成這一合併過程。排序
接下來咱們來解決魯棒性的問題。每當代碼試圖訪問空指針指向的內存時 程序就會崩潰,從而致使魯棒性問題。在本題中一旦輸入空的鏈表就會引入空的指針,所以咱們要對空鏈表單獨處理。當第一個鏈表是空鏈表,也就是它的頭結點是 一個空指針時,那麼把它和第二個鏈表合併,閒人合併的過程就是第二個鏈表。一樣,當輸入的第二個鏈表的頭結點是空指針的時候,咱們把它和第一個鏈表合併得 到的結果就是第一個鏈表。若是兩個鏈表都是空鏈表,合併的結果是獲得一個空鏈表。遞歸
下面是Java代碼的實現:內存
package cglib;
class ListNode
{
int data;
ListNode nextNode;
}get
public class DeleteNode {
public static void main(String[] args) {
ListNode head1=new ListNode();
ListNode second1=new ListNode();
ListNode head2=new ListNode();
ListNode second2=new ListNode();
ListNode third2=new ListNode();
head1.nextNode=second1;
head2.nextNode=second2;
second2.nextNode=third2;
head1.data=1;
second1.data=3;
head2.data=2;
second2.data=2;
third2.data=2;
DeleteNode test=new DeleteNode();
ListNode result=test.reverseList(head1, head2);
System.out.println(result.nextNode.nextNode.nextNode.nextNode.data);
}
public ListNode reverseList(ListNode head1,ListNode head2){
if(head1==null&&head2!=null){
return head2;
}
else if(head2==null&&head1!=null){
return head1;
}
else if(head2==null&&head1==null){
return null;
}
else
{
ListNode mergeHead=null;
if(head1.data<head2.data){
mergeHead=head1;
mergeHead.nextNode=reverseList(head1.nextNode,head2);
}else{
mergeHead=head2;
mergeHead.nextNode=reverseList(head1, head2.nextNode);
}
return mergeHead;
}
}
}class