06 从尾到头打印新链表

题目描述:

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

解题思路:

1)使用list容器:顺序访问链表,使用push_front()将元素插入list容器的前方。

2)使用栈

3)使用递归函数:递归在本质上是一个栈结构

4)用反向迭代器(object.rbegin(), object.rend()

5)头插法(复杂度高)

测试用例:

1)功能测试:(输入的链表有多个节点;只有一个节点)

2)特殊输入测试:(输入的链表头节点指针为nullptr)

代码:



1)使用list容器:

 1 /**
 2 *  struct ListNode {
 3 *        int val;
 4 *        struct ListNode *next;
 5 *        ListNode(int x) :
 6 *              val(x), next(NULL) {
 7 *        }
 8 *  };
 9 */
10 class Solution {
11 public:
12     vector<int> printListFromTailToHead(ListNode* head) {
13         if (head==NULL)
14             return vector<int>{};  //error: return 0;nullptr;vector<int>{0};
15         vector<int> res;
16         list<int> bactToFront;
17         ListNode* currentNode = head;
18         while (currentNode!=NULL){ //error : currentNode->next
19             bactToFront.push_front(currentNode->val);
20             currentNode = currentNode->next;
21         }
22         //遍历bactToFront,按顺序复制给vector
23         //for(int i=0;i<bactToFront.size();i++)
24             //res.push_back(bactToFront[i]); // bactToFront[i]: type ‘list‘ does not provide a subscript operator
25         for(auto iter = bactToFront.begin();iter!=bactToFront.end();iter++)//list<int>::iterator
26             res.push_back(*iter);
27         return res;
28     }
29 };

List

注意:

「1」链表为空<=>头指针为空,即判断head==NULL。而不是head->next==NULL

「2」当链表为空的时候,不用处理任何步骤,直接返回即可。由于返回值是vector<int>值。因此return vector<int>{};

此处,返回0;nullptr;vector<int>{0};vector<int>;都是错的。

「3」判断链表是否结束:当前指针域不为空,即:currentNode!=NULL(证明指向下一个节点)

而不是currentNode->next!=NULL(说明当前指针的下一个节点有后继节点,此种情况最后一个节点访问不到)

「4」遍历list容器应该使用迭代器,list不支持下标访问。



2)使用栈:

 1 /**
 2 *  struct ListNode {
 3 *        int val;
 4 *        struct ListNode *next;
 5 *        ListNode(int x) :
 6 *              val(x), next(NULL) {
 7 *        }
 8 *  };
 9 */
10 class Solution {
11 public:
12     vector<int> printListFromTailToHead(ListNode* head) {
13         if (head==NULL)
14             return vector<int>{};  //error: return 0;nullptr;vector<int>{0};
15         vector<int> res;
16         stack<int> frontToBack;
17         ListNode* currrent = head;
18         while(currrent!=NULL){
19             frontToBack.push(currrent->val); //stack 存储使用函数push()
20             currrent = currrent->next;
21         }
22         int len = frontToBack.size();
23         for(int i = 0;i<len;i++){ //
24             res.push_back(frontToBack.top()); //读取栈顶元素
25             frontToBack.pop(); //删除栈顶元素
26         }
27         return res;
28     }
29 };

stack

注意:

「1」Stack(栈)是一种后进先出的数据结构,也就是LIFO(last in first out) ,最后加入栈的元素将最先被取出来,在栈的同一端进行数据的插入与取出,这一段叫做“栈顶”。

「2」stack 存储使用函数push() (将元素加入栈中,没有返回值)

「3」size()函数返回栈的大小

「4」empty()函数返回一个bool值,栈为空时返回true,否则返回false

「5」top()函数的返回值是栈顶元素(注意并没有删掉栈顶元素),即读取栈顶元素。

「6」pop()函数将栈顶元素删掉,没有返回值

「7」swap()函数可以交换两个栈的元素

「8」emplace()函数可以将一个元素加入栈中,与push的区别在于:

· stack<Node> mystack;

· mystack.emplace(1,2);

· mystack.push(Node(1,2));

emplace可以直接传入Node的构造函数的参数,push需要手动构造。

「9」错误代码:

1 for(int i = 0;i<frontToBack.size();i++){ //
2      res.push_back(frontToBack.top()); //读取栈顶元素
3      frontToBack.pop(); //删除栈顶元素
4 }

line 1的frontToBack.size()一直在改变(因为每次循环都会删除一个元素)

修改如下:

1 int len = frontToBack.size();
2 for(int i = 0;i<len;i++){ //
3      res.push_back(frontToBack.top()); //读取栈顶元素
4      frontToBack.pop(); //删除栈顶元素
5  }

「10」使用while读取stack

1 while(!stack.empty()) {

2     res.push_back(frontToBack.top());

3     frontToBack.pop();

4 }



3)使用递归函数:

 1 class Solution {
 2  public:
 3   vector<int> dev;
 4   vector<int>& printListFromTailToHead(ListNode* head) {
 5     if(head!=NULL) {
 6       if(head->next!=NULL) {
 7         dev=printListFromTailToHead(head->next);
 8       }
 9       dev.push_back(head->val);
10     }
11     return dev;
12   }
13 };

recursion

注意:

「1」基于递归的代码看起来很简洁,但是有一个问题:当链表非常长的时候,就会导致函数调用的层级很深,从而有可能导致函数调用栈溢出。

「2」推荐使用栈结构(stack)



4)用反向迭代器 :

 1 class Solution {
 2 public:
 3     vector<int> printListFromTailToHead(ListNode* head) {
 4         if (head==NULL)
 5             return vector<int>{};  //error: return 0;nullptr;vector<int>{0};
 6         vector<int> res;
 7         ListNode* currrent = head;
 8         while(currrent!=NULL){
 9             res.push_back(currrent->val); //stack 存储使用函数push()
10             currrent = currrent->next;
11         }
12         return vector<int>(res.rbegin(),res.rend()); //返回一个临时对象
13     }
14 };

rbegin/rend

注意:

「1」获取迭代器:c.begin()  c.end()   返回指向c的首元素和尾元素之后位置的迭代器  (end并不是返回尾元素)

c.cbegin()  c.cend()   返回const_iterator

「2」反向容器的额外成员(不支持forward_list):

    reverse_iterator  按逆序寻址元素的迭代器

    const_reverse_iterator  不能修改元素的逆序迭代器

c.rbegin()  c.rend()  返回指向c的尾元素和首元素之前的位置的迭代器

    c.crbegin()  c.crend()  返回const_reverse_iterator



5)头插法(复杂度高)

 1 class Solution {
 2 public:
 3 vector<int> printListFromTailToHead(ListNode* head) {
 4         vector<int> v;
 5         while(head != NULL)
 6         {
 7             v.insert(v.begin(),head->val);
 8             head = head->next;
 9         }
10         return v;
11     }
12 };

head_insert

注意:
 v.insert(v.begin(),head->val); 等价于 v.push_front(head->val);
每次插入相当于把当前数组元素全部向后移动一个位置,再插入当前元素,这一块的时间复杂度就是O(n^2),效率低。



基础知识:

链表结构,基础 推荐博客:

https://www.cnblogs.com/byonecry/p/4458821.html

https://i.cnblogs.com/EditPosts.aspx?postid=9966012&update=1

原文地址:https://www.cnblogs.com/GuoXinxin/p/9966012.html

时间: 2024-10-10 06:33:59

06 从尾到头打印新链表的相关文章

LeetCode | 面试题06. 从尾到头打印链表【剑指Offer】【Python】

LeetCode 面试题06. 从尾到头打印链表[剑指Offer][Easy][Python][链表] 问题 力扣 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回). 示例 1: 输入:head = [1,3,2] 输出:[2,3,1] 限制: 0 <= 链表长度 <= 10000 思路 解法一 reverse函数 时间复杂度: O(n),n为 head 链表长度. 空间复杂度: O(n),n为 head 链表长度. Python3代码 # Definition for si

从尾到头打印一个链表

1.利用jdk的链表数据结构实现: /** * 问题7.从尾到头打印列表 用jdk的LinkList * */ @Test public void print_reverse_LinkedList(){ LinkedList<Person> list = new LinkedList<Person>(); for (int i =5;i>0;i--){ Person p1 = new Person(); p1.setName("Alice"+i); p1.

从尾到头打印链表-剑指Offer

从尾到头打印链表 题目描述 输入一个链表,从尾到头打印链表每个节点的值 输入描述 输入为链表的表头 输出描述 输出为需要打印的“新链表”的表头 思路 单向链表是从头到尾指向的,从尾到头打印符合“后进先出”,所以我们使用栈结构Stack 代码 import java.util.ArrayList; import java.util.Stack; public class Solution03 { public ArrayList<Integer> printListFromTailToHead(

输入一个链表,从尾到头打印链表每个节点的值

题目描述: 输入一个链表,从尾到头打印链表每个节点的值. 输入描述: 输入为链表的表头 输出描述: 输出为需要打印的"新链表"的表头 用栈处理: /** *    public class ListNode { *        int val; *        ListNode next = null; * *        ListNode(int val) { *            this.val = val; *        } *    } * */ import 

剑指offer——从尾到头打印链表节点的值

输入一个链表,从尾到头打印链表每个节点的值. 输入描述:输入为链表的表头 输出描述:输出为需要打印的“新链表”的表头 一.问题分析 初拿到这个题目时,这应该是考察单向链表这一数据结构.单向链表的遍历总是从头指针逐项遍历各个节点,现在要求从尾到头打印节点的值,我们可以在遍历时把各节点压入栈内,最后出栈打印各个节点值,即可达到要求. 实现之前,我们先来看看如何创建一个链表. 1,链表节点的数据结构定义 1 struct ListNode { 2 int val; 3 struct ListNode

《剑指offer》第五题(重要!从尾到头打印链表)

文件main.cpp // 从尾到头打印链表 // 题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值. #include <iostream> #include <stack> #include "List.h" using namespace std; void PrintListReversingly_Iteratively(ListNode* pHead)//解法一:使用栈 { stack<ListNode*> nodes;//定义

《剑指Offer》题目——从尾到头打印链表

题目描述:输入一个链表,从尾到头打印链表每个节点的值. 题目分析:用栈:Java用Stack不如用Deque接口,原因可以见链接:http://stackoverflow.com/questions/12524826/why-should-i-use-deque-over-stack public class ReverseList { class ListNode{ int val; ListNode next = null; ListNode(int val){ this.val = val

从尾到头打印链表

参与人数:4164时间限制:1秒空间限制:32768K 通过比例:16.80% 最佳记录:0 ms|0K(来自  黄昏的足迹) 题目描述 输入一个链表,从尾到头打印链表每个节点的值. 提交时间:2015-09-25 语言:C++ 运行时间:0ms 占用内存:8552K 状态:答案正确 /* 遍历一次链表,每遍历到一个结点,就将结点的值插入到vecotr的开始. */ /** * struct ListNode { * int val; * struct ListNode *next; * Lis

5-从尾到头打印链表

题目描述:http://ac.jobdu.com/problem.php?pid=1511 输入一个链表,从尾到头打印链表每个节点的值. 输入: 每个输入文件仅包含一组测试样例. 每一组测试案例包含多行,每行一个大于0的整数,代表一个链表的节点.第一行是链表第一个节点的值,依次类推.当输入到-1时代表链表输入完毕.-1本身不属于链表. 输出: 对应每个测试案例,以从尾到头的顺序输出链表每个节点的值,每个值占一行. 逆序打印链表,我们遍历链表只能从头到尾,现在要求我们从尾到头.后进先出,可以想到用