题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。(牛客网编程版)
与面试官确定题意:因为是从尾到头反过来打印每个结点,则要确定一下可不可以改变原来的链表结构?
下面,我将从改变链表结构和不改变链表结构来分析:
通常打印是一个只读操作,不希望修改打印的内容,所以我们先从不改变链表结构来分析
从尾到头打印,跟栈的后进先出的模式有点相似,可以考虑使用栈来处理:
如下面代码所示,先遍历所有的结点,同时压入栈中,直到链表尾。最后从栈的顶端打印结点,弹出结点直到栈为空。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
void printListFromTailToHead(struct ListNode* head) {
std::stack<ListNode *> nodes;
ListNode* pNode = head;
while(pNode != NULL){
nodes.push(pNode);
pNode = pNode->next;
}
while(!nodes.empty()){
std::cout << nodes.top()->val;
nodes.pop();
}
}
};
还有一种方法是使用递归的方法,因为递归本质上就是一个栈的结构。不过,在处理链表的时候,有一些出错问题需要考虑的,例如链表为空,当你需要用到结点的下一个结点的时候,就需要考虑只有一个元素应该怎样处理。
class Solution {
public:
void printListFromTailToHead(struct ListNode* head) {
if(head != NULL)
{
if (head->next != NULL)
{
printListFromTailToHead(head->next);
}
cout << head->val;
}
}
};
牛客网上的函数形式跟书本上不一样,它是返回一个vector<int>类数据,我们可以使用vector的库函数Insert来简化代码。开辟一个新的空间,然后调用vector容器的插值的方法,把链表的反向结构存放在容器里面。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(struct ListNode* head) {
vector<int> temp;
while(head != NULL){
temp.insert(temp.begin(), head->val);
head = head->next;
}
return temp;
}
};
另外一种方法就是修改链表的结构,也就是先对链表进行反转,再遍历打印,可见博客:
如上面代码所示,先遍历所有的结点,同时压入栈中,直到链表尾。最后从栈的顶端打印结点,弹出结点直到栈为空。