剑指Offer面试题5(Java版):从尾到头打印链表
2015-07-25 09:24
555 查看
题目:输入一个链表的头结点,从尾到头反过来打印出每个节点的值。
看到这道题,很多人的第一反应是从头到尾输出将会比较简单,于是我们很自然的想到把链表中的节点的指针反转过来,改变链表的方向,然后就可以从头到尾输出了。但该方法改变原来链表的结构。是否允许在打印链表的时候修改链表的结构?这个取决于面试官的要求,因此在面试的时候我们要询问清楚面试官的要求。
通常打印是一个只读操作,我们不希望打印时修改内容。假设面试官也要求这个题目不能改变链表的结构。
接下来我们想到解决这个问题肯定要遍历链表。遍历的顺序是从头到尾的顺序,可输出的顺序却是从尾到头。也就是说第一个遍历的节点最后一个输出,而最后一个遍历到的节点第一个输出。这就是典型的'后进先出“,我们可以从栈实现这种顺序。没经过一个节点的时候,把该节点放到一个栈中。当遍历完整的链表后,再从栈顶开始逐个输出节点的值,此时输出的节点的顺序已经反转过来了。
既然想到了用栈来实现这个函数,而递归在本身上就是一个栈结构,于是自然就想到了用递归来实现。要实现反过来输出链表,我们没访问到一个节点的时候,先递归输出后面的 节点,再输出该节点本身,这样链表的输出结果就反过来了。
实现代码如下:
上面的基于递归的代码看起来很简洁,但有个问题:当链表非常长的时候,就会导致函数调用的层级很深,从而有可能导致函数调用栈溢出。显式用栈基于循环的代码的鲁棒性要好一些。
看到这道题,很多人的第一反应是从头到尾输出将会比较简单,于是我们很自然的想到把链表中的节点的指针反转过来,改变链表的方向,然后就可以从头到尾输出了。但该方法改变原来链表的结构。是否允许在打印链表的时候修改链表的结构?这个取决于面试官的要求,因此在面试的时候我们要询问清楚面试官的要求。
通常打印是一个只读操作,我们不希望打印时修改内容。假设面试官也要求这个题目不能改变链表的结构。
接下来我们想到解决这个问题肯定要遍历链表。遍历的顺序是从头到尾的顺序,可输出的顺序却是从尾到头。也就是说第一个遍历的节点最后一个输出,而最后一个遍历到的节点第一个输出。这就是典型的'后进先出“,我们可以从栈实现这种顺序。没经过一个节点的时候,把该节点放到一个栈中。当遍历完整的链表后,再从栈顶开始逐个输出节点的值,此时输出的节点的顺序已经反转过来了。
既然想到了用栈来实现这个函数,而递归在本身上就是一个栈结构,于是自然就想到了用递归来实现。要实现反过来输出链表,我们没访问到一个节点的时候,先递归输出后面的 节点,再输出该节点本身,这样链表的输出结果就反过来了。
实现代码如下:
<pre name="code" class="java">package offer; import java.util.Stack; class Node { public int data; public Node nextNode; public Node() { } public Node(int data) { this.data = data; } } public class E05FromTailToStart { public static void main(String[] args) { Node start = new Node(1); Node two = new Node(2); start.nextNode = two; // Node two = new Node(2); // start.nextNode = two; printTailToStartRec(start); printTailToStartStack(start); } // 采用递归调用的方法 private static void printTailToStartRec(Node start) { if (start != null) { if (start.nextNode != null) { printTailToStartRec(start.nextNode); } System.out.println(start.data); } else{ System.out.println("list is null!"); } } // 采用栈--先进后出的方法 private static void printTailToStartStack(Node node) { if (node == null) { System.out.println("list is null"); return; } Stack<Node> stack = new Stack<Node>(); while (node != null) { stack.push(node); node = node.nextNode; } while (!stack.isEmpty()) { System.out.println(stack.pop().data); } } }
上面的基于递归的代码看起来很简洁,但有个问题:当链表非常长的时候,就会导致函数调用的层级很深,从而有可能导致函数调用栈溢出。显式用栈基于循环的代码的鲁棒性要好一些。
相关文章推荐
- 黑马程序员——Java IO总结一
- 程序员,为什么千万不要重写代码?
- 关于“构造函数”中的几个小问题,也许面试会问到哦~
- 神奇的decimal,也许面试会问到哦~
- 【黑马程序员】----java基础---反射
- 黑马程序员——Java基础-异常
- 【LeetCode-面试算法经典-Java实现】【029-Divide Two Integers(两个整数相除)】
- 【LeetCode-面试算法经典-Java实现】【028-Implement strStr() (实现strStr()函数)】
- 【LeetCode-面试算法经典-Java实现】【027-Remove Element(删除数组中指定的元素)】
- 程序员,为什么千万不要重写代码?
- Two Sigma面试专题
- 阿里电话面试问题----100万个URL如何找到出现频率最高的前100个?
- 黑马程序员--面向对象02
- 【面试加分项】java自定义注解之申明注解
- 第一次使用拉勾网求职经历
- 全面解析《嵌入式程序员应该知道的16个问题》
- 出来行迟早是要还的(篇四):游戏开发离职日志和面试日志
- 程序员技术练级攻略(转)
- 黑马程序员--面向对象01
- 黑马程序员——Java基础-多态