面试题5:从尾到头打印链表
题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。链表结点定义如下:
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
方法一:递归
这里选择了递归的方式,当递归到最底层的时候,呈现给我们的数值是链表的最后一位。这个时候我们用ArrayList<Integer>接收。
最终ArrayList<Integer>中存储的值的顺序就是链表从尾到头的数值的顺序。我们直接遍历ArrayList<Integer>即可。
但是这种方法有缺陷,当链表长度过长的时候,会使得递归的深度会很大,有可能导致栈的溢出。
public class Solution {
ArrayList<Integer> arrayList = new ArrayList<>();
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if (listNode != null) {
printListFromTailToHead(listNode.next);
arrayList.add(listNode.val);
}
return arrayList;
}
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
}
方法二:利用栈
利用栈先进后出的特点: 创建一个栈顺序接收链表的数值,然后遍历栈实现数值排列逆序的输出。相对于递归,我认为这是一种更合适的方法。
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if (listNode == null) {
ArrayList<Integer> arrayList = new ArrayList<>();
return arrayList;
}
//定义一个栈
Deque<Integer> stack = new ArrayDeque<>();
while (listNode != null) {
stack.push(listNode.val);//入栈
listNode = listNode.next;
}
while (!stack.isEmpty()) {
arrayList.add(stack.pop());//出栈,并添加到arrayList
}
return arrayList;
}
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
}
链表是一种动态数据结构,是因为在创建链表时,无须知道链表的长度。当插入一个结点时,我们只需要为新结点分配内存,然后调整指针的指向来确保新结点被链接到链表当中。内存分配不是在创建链表时一次性完成,而是每添加一个结点分配一次内存。由于没有闲置的内存,链表的空间效率比数组高。
由于链表非常灵活而且代码相对简练的特点,在面试中考察的是非常多的。