zoukankan      html  css  js  c++  java
  • 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

    prac 02 

    //如果需要修改原始数据,最好询问一下面试官。 通常打印是只读工作,不修改内容
    //考虑使用栈实现
    //递归的本质是栈结构,考虑使用递归实现
    class Solution {
    public:
        vector<int> printListFromTailToHead(ListNode* head) {
            stack<int> array;
            while (head != nullptr){ //null error
                array.push(head->val);
                head = head->next;
            }
            vector<int> ArrayList;
            while(!array.empty()){
                ArrayList.push_back(array.top());
                array.pop();
            }
            return ArrayList;
            
        }
    };
    

     

    //如果需要修改原始数据,最好询问一下面试官。 通常打印是只读工作,不修改内容
    //递归的本质是栈结构,考虑使用递归实现
    //先递归输出后面的节点,在输出该节点自身
    class Solution {
    public:
        vector<int> printListFromTailToHead(ListNode* head) {
            vector<int> ArrayList;
            if (head!=nullptr){
                if (head->next!=nullptr){
                    ArrayList = printListFromTailToHead(head->next);
                }
                ArrayList.push_back(head->val);// return the last elements
            }
            return ArrayList;
        }
    };
    

      

    #prac autumn

     1 class Solution {
     2 public:
     3     vector<int> printListFromTailToHead(ListNode* head) {
     4         vector<int> res;
     5         if(head==nullptr)
     6             return res;
     7         ListNode* p = head;
     8         while(p){
     9             res.push_back(p->val);
    10             p = p->next;
    11         }
    12         reverse(res.begin(),res.end());
    13         return res;
    14     }
    15 };
    View Code

     

  • 相关阅读:
    修改spring MVC配置文件的默认位置
    TCP三次握手四次挥手视频讲解
    Redis端口配置
    applicationContext-redis.xml
    PageHelper的分页原理
    maven的三种工程 pom工程、jar工程、war工程的区别和使用
    springboot 整合spring Data JPA的资源配置pom.xml
    Spring知识点整理
    jdk1.6 和 jdk1.7 区别
    linux中安装redis
  • 原文地址:https://www.cnblogs.com/GuoXinxin/p/9966012.html
Copyright © 2011-2022 走看看