题目
输入一个链表的头节点,从尾到头反过来打印出每个节点的值
题目分析
单向链表只能从前往后遍历,给出头节点,如果正向打印是很容易的一件事,如果反向打印,就相对麻烦了。因为单向链表的特性我们无法从后往前遍历,那么就需要一种“后进先出”的数据结构或者方法来解决这个问题。而“栈”就是这样一种数据结构。
第一种解法:通过遍历链表,将每个节点的值压入栈,然后再把栈里的值一个一个弹出即可。
第二种解法:使用递归,递归和栈的原理非常相似。
第三种解法:通过数组,先遍历一遍链表,通过累加拿到链表长度,然后创建一个数组,在遍历一次链表,将每个节点的值放入数组,最后反向打印出数组即可。
这道题放java里有太多解决方式了,但是这道题主要是考察对链表,栈,递归,循环等的了解。不是说能打印出来就完事了的。上边3种解法里,第一种为最优解,第二种的递归能不用就不用,在任何程序语言里都是一个道理,能用循环实现的就不要用递归,除非万不得以。递归每次都会创建一个栈帧,太多层递归可能栈溢出,JVM会先被无穷无尽的栈帧撑爆。递归基本上都可以转由循环实现,优先考虑循环。最后一种解法比上边2种解法多了一次遍历,虽然最终时间复杂度也是O(n),算是我自己的解法,哈哈。
代码实现
package day2;
import java.util.Stack;
/**
* 方向打印单向链表
* <p>面试题5:输入一个链表的头节点,从尾到头反过来打印出每个节点的值</p>
* @author leoss
* @version 2019/1/3 23:22
*/
public class PrintLink {
public static void main(String[] args) {
int size = 5;
Node head = genLink(size);
printLinkByLoop(head);
// printLinkByRecursion(head);
// printLinkByArray(head);
size = 0;
head = genLink(size);
printLinkByLoop(head);
// printLinkByRecursion(head);
// printLinkByArray(head);
printLinkByLoop(null);
// printLinkByRecursion(null);
// printLinkByArray(null);
}
static class Node {
int val;
Node next;
}
/**
* 生成指定长度的链表
*
* @param size 链表长度
* @return 链表
*/
private static Node genLink(int size) {
Node head = null;
Node now = null;
for (int i = 0; i < size; i++) {
Node node = new Node();
node.val = i;
if (i == 0) {
head = node;
now = head;
} else {
now.next = node;
now = node;
}
}
return head;
}
/**
* 递归实现反向打印链表
*
* @param node 链表头节点
*/
private static void printLinkByRecursion(Node node) {
if (node != null) {
if (node.next != null) {
printLinkByRecursion(node.next);
}
System.out.println("rec : " + node.val);
} else {
System.err.println("link is null");
}
}
/**
* 循环实现反向打印链表
*
* @param node 链表头节点
*/
private static void printLinkByLoop(Node node) {
if (node == null) {
System.err.println("link is null");
return;
}
Stack<Integer> stack = new Stack<>();
while (node != null) {
stack.push(node.val);
node = node.next;
}
while (!stack.isEmpty()) {
//注意这里是用pop,不是用peek
System.out.println("loop : " + stack.pop());
}
}
/**
* 数组实现反向打印链表
*
* @param node 链表头节点
*/
private static void printLinkByArray(Node node) {
int size = 0;
Node tmp = node;
while (tmp != null) {
size++;
tmp = tmp.next;
}
Node[] nodes = new Node[size];
for (int i = 0; i < size; i++) {
nodes[i] = node;
node = node.next;
}
for (int i = size - 1; i >= 0; i--) {
System.out.println("arr : " + nodes[i].val);
}
}
}
测试用例
int size = 5;
Node head = genLink(size);
printLinkByLoop(head);
// printLinkByRecursion(head);
// printLinkByArray(head);
size = 0;
head = genLink(size);
printLinkByLoop(head);
// printLinkByRecursion(head);
// printLinkByArray(head);
printLinkByLoop(null);
// printLinkByRecursion(null);
// printLinkByArray(null);
测试结果
loop : 4
loop : 3
loop : 2
loop : 1
loop : 0
link is null
link is null