此题大意是有两个已经排好序的有序链表,需要将他们合并起来,最后想出来的答案是下面这种比较常规的做法:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode head = new ListNode(0);
ListNode handler = head;
while(l1 != null && l2 != null) {
if (l1.val <= l2.val) {
handler.next = l1;
l1 = l1.next;
} else {
handler.next = l2;
l2 = l2.next;
}
handler = handler.next;
}
if (l1 != null) {
handler.next = l1;
} else if (l2 != null) {
handler.next = l2;
}
return head.next;
}
}
做完后照例去评论区翻看,然后看到了下面这种骚气的方法
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null)return l2;
if(l2 == null)return l1;
if(l1.val<l2.val){
l1.next = mergeTwoLists(l1.next,l2);
return l1;
} else {
l2.next = mergeTwoLists(l1,l2.next);
return l2;
}
}
}
看到这个方法真的是当即66666666,使用了递归(recursion)后令代码如此简洁优雅,简直就是一首诗,但是我们需要注意的是其中的现实问题
Because in real life, the length of a linked list could be much longer than we expected, in which case the recursive approach is likely to introduce a stack overflow. (Imagine a file system)
这是其中一条评论,具体大意是在现实生活中我们需要考虑到stack overflow(堆栈溢出),即不顾堆栈中分配的局部数据块大小,向该数据块写入了过多的数据,导致数据越界,结果覆盖了老的堆栈数据。我们可以从递归与栈的关系去理解:
函数的递归调用和普通函数调用是一样的。当程序执行到某个函数时,将这个函数进行入栈操作,在入栈之前,通常需要完成三件事。
1、将所有的实参、返回地址等信息传递给被调函数保存。
2、为被调函数的局部变量分配存储区。
3、将控制转移到被调函数入口。
当一个函数完成之后会进行出栈操作,出栈之前同样要完成三件事。
1、保存被调函数的计算结果。
2、释放被调函数的数据区。
3、依照被调函数保存的返回地址将控制转移到调用函数。
上述操作必须通过栈来实现,即将整个程序的运行空间安排在一个栈中。每当运行一个函数时,就在栈顶分配空间,函数退出后,释放这块空间。所以当前运行的函数一定在栈顶。
(注:摘自严蔚敏等人的数据结构c语言版)
由上我们可以看出,这个用来运行此段程序的运行空间(栈),有可能会因为数据量过大而溢出,明显不利于我们的实际开发。
所以若在面试中碰到此题,且使用了第二种方法的话,记得跟面试官声明这个实际问题。