从尾到头打印单链表

问题描述:输入一个链表,从尾到头打印链表每个节点的值。

函数接口:vector< int > printListFromTailToHead(ListNode* head)

这个题的解法呢有下面几种
1.不根据这个接口写的话就是直接递归从头到尾打印单链表

2.根据接口写的话,首先因为给的接口的返回值是一个vector类型的,所以我们可以推断出应该是将链表中的元素从尾到头放在vector中,然后将vector返回去,所以
①利用递归遍历单链表将元素从尾到头放进vector中
②利用栈的特性,从头到尾遍历单链表,将其元素依次入栈,然后在将栈顶元素弹出,压入vector中
③利用vector的特性,从头到位遍历单链表,然后头插到vector中,这样最后的vector中元素的顺序就是单链表的逆序顺序

下面一次给出每个代码的算法实现,顺序根据上面描述算法的顺序
1.不根据接口写

    void  printListFromTailToHead1(pListNode _head)
    {
        if (_head == NULL)
            return;
        printListFromTailToHead1(_head->next);
        cout << _head->_data << " ";
    }

根据接口写
2.也是利用递归

vector<int> printListFromTailToHead2(ListNode* head)//逆序输出单链表正常方法
    {
        if (head != NULL)
        {
            if (head->next != NULL)
            {
                s = printListFromTailToHead2(head->next);
            }
            s.push_back(head->_data);
        }
        return s;//这里的s是我定义好的vector
    }

3.根据栈的特性

vector<int> printListFromTailToHead3(ListNode* head)//方法3
    {
        stack<int> st;
        while (head)
        {
            st.push(head->_data);
            head = head->next;
        }
        while (!st.empty())
        {
            s.push_back(st.top());
            st.pop();
        }
        return s;
    }

4.利用vector的特性

vector<int> printListFromTailToHead4(ListNode* head)
    {
                while (head != NULL)
                {
                    s.insert(s.begin(), head->_data);
                    head = head->next;
                }
                return s;
    }

下面再给出我测试的单链表部分的代码

注意我创建的单链表的顺序是:1 2 3 4 5

typedef struct ListNode//单链表的结点
{
    int _data;
    ListNode *next;
    ListNode(int data)
        :_data(data)
        , next(NULL){}
    ListNode()
        :next(NULL){}
}*pListNode;

class Node
{
private:
    vector<int> s;
    pListNode head;//头指针
public:
    Node(int *array, int size)//构造函数创建无头单链表
        :head(NULL)
    {
        for (int i = 0; i < size; i++)
        {
            if (head == NULL)
            {
                head = new ListNode(array[i]);
                head->next = NULL;
            }
            else
            {
                pListNode cur = new ListNode(array[i]);
                cur->next = head;
                head = cur;
            }
        }
    }
    ~Node()//析构函数
    {
        while (head != NULL)
        {
            pListNode cur = head;
            head = head->next;
            delete cur;
        }
    }
};

下面给出完整的代码和测试结果

#include<iostream>
#include<vector>
#include<stack>
using namespace std;
typedef struct ListNode
{
    int _data;
    ListNode *next;
    ListNode(int data)
        :_data(data)
        , next(NULL){}
    ListNode()
        :next(NULL){}
}*pListNode;

class Node
{
private:
    vector<int> s;
    pListNode head;//头指针
public:
    Node(int *array, int size)//构造函数创建无头单链表
        :head(NULL)
    {
        for (int i = 0; i < size; i++)
        {
            if (head == NULL)
            {
                head = new ListNode(array[i]);
                head->next = NULL;
            }
            else
            {
                pListNode cur = new ListNode(array[i]);
                cur->next = head;
                head = cur;
            }
        }
    }
    ~Node()//析构函数
    {
        while (head != NULL)
        {
            pListNode cur = head;
            head = head->next;
            delete cur;
        }
    }
    void  _printListFromTailToHead1()//没有使用接口的递归打印
    {
        printListFromTailToHead1(head);
    }
    vector<int> _printListFromTailToHead2()//使用接口的递归打印,这里用进行了封装
    {
        s = printListFromTailToHead2(head);
        return s;
    }
    vector<int> _printListFromTailToHead3()//使用接口的栈的特性
    {
        s= printListFromTailToHead3(head);
        return s;
    }
    vector<int> _printListFromTailToHead4()//使用vector的特性
    {
        s = printListFromTailToHead4(head);
        return s;
    }
private:
    void  printListFromTailToHead1(pListNode _head)//没有使用接口的递归打印
    {
        if (_head == NULL)
            return;
        printListFromTailToHead1(_head->next);
        cout << _head->_data << " ";
    }
    vector<int> printListFromTailToHead2(ListNode* head)//使用接口递归
    {   if (head != NULL)
        {
            if (head->next != NULL)
            {
                s = printListFromTailToHead2(head->next);
            }
            s.push_back(head->_data);
        }
        return s;//这里的s是我定义好的vector
    }
    vector<int> printListFromTailToHead3(ListNode* head)//使用接口利用栈的性质
    {
        stack<int> st;
        while (head)
        {
            st.push(head->_data);
            head = head->next;
        }
        while (!st.empty())
        {
            s.push_back(st.top());
            st.pop();
        }
        return s;
    }
    vector<int> printListFromTailToHead4(ListNode* head)//使用接口利用vector的性质
    {
                while (head != NULL)
                {
                    s.insert(s.begin(), head->_data);
                    head = head->next;
                }
                return s;
    }
};
int main()
{
    int arr[5] = { 5, 4, 3, 2, 1 };
    vector<int> test;
    Node LT(arr, 5);
    LT._printListFromTailToHead1();
    test=LT._printListFromTailToHead2();
    test = LT._printListFromTailToHead3();
    test = LT._printListFromTailToHead4();
    system("pause");
    return 0;
}

因为没有用接口的函数直接打印出来的而其余的没有打印,所以测试结果如下
这里写图片描述
这里写图片描述

<think>嗯,用户想了解如何在C++中实现从到头打印单链表,而且不使用虚拟头结点,同时还要给主函数添加注释。首先,我需要回顾一下单链表的基本结构和遍历方法。通常,单链表的遍历是从头节点开始,逐个访问直到末。但这里要求逆序打印,也就是说需要先处理后面的节点,再处理前面的节点。这让我想到两种常见的方法:递归和栈。因为这两种方式都能利用后进先出的特性来实现逆序。 用户提到不使用虚拟头节点,这意味着不需要额外的头节点来辅助操作,直接处理原始链表即可。对于递归方法,思路应该是递归链表,然后逐层返回时输出节点的值。这样自然就形成了逆序。但是需要注意递归的终止条件,即当前节点为空时返回,否则先递归调用下一个节点,再输出当前节点的数据。这种方法代码简洁,但链表过长时可能导致栈溢出,这是一个潜在的缺点。 另一种方法是使用栈。栈的先进后出特性正好符合逆序的需求。遍历链表,将每个节点依次入栈,遍历完成后,依次出栈并输出节点值。这种方法需要额外的栈空间,但避免了递归的栈溢出问题,适合较长的链表。 接下来需要为主函数添加注释。主函数应该包括创建链表、调用逆序打印函数。创建链表可以通过循环添加节点来实现,比如用户输入一组数字,逐个插入链表。然后调用递归或栈的方法进行逆序打印。注释需要说明每一步的操作,比如创建节点、链接节点、调用函数等。 还需要考虑代码的正确性。比如,在递归方法中,递归调用必须在输出之前,否则会变成正序打印。栈的实现中,确保所有节点都被正确压入栈中,然后按顺序弹出。同时,内存管理方面,如果链表是动态分配的,应该在主函数结束时释放内存,但用户可能没有提到这一点,可能需要补充说明或者假设链表由用户自行管理。 参考站内的引用中,引用[3]提到了递归实现二叉树中序遍历,这和递归打印链表有相似之处,都是利用递归的回溯过程来处理节点。引用[1]于右值引用的内容可能不直接相,但需要注意在C++代码中正确使用引用和指针。 最后,用户需要主函数的注释,所以代码中应该详细说明每一步的作用,比如如何构建链表,如何调用逆序函数,参数的意义等。同时,示例代码需要符合C++语法,比如使用结构体定义节点,正确处理指针等。</think>### C++实现单链表逆序打印(不使用虚拟头结点) 以下使用递归和栈两种方式实现,包含完整的主函数实现与注释: ```cpp #include <iostream> #include <stack> using namespace std; // 链表节点结构体 struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} }; // 递归方式实现(时间复杂度O(n),空间复杂度O(n)) void reversePrintRecursive(ListNode* node) { if (!node) return; // 递归终止条件 reversePrintRecursive(node->next); // 先递归链表 cout << node->val << " "; // 回溯时输出 } // 栈方式实现(时间复杂度O(n),空间复杂度O(n)) void reversePrintStack(ListNode* head) { stack<ListNode*> st; while (head) { // 将所有节点压入栈 st.push(head); head = head->next; } while (!st.empty()) { // 依次弹出栈顶元素 cout << st.top()->val << " "; st.pop(); } } int main() { // 创建示例链表 1->2->3->4->5 ListNode* head = new ListNode(1); // 头节点 ListNode* cur = head; // 当前指针 for (int i = 2; i <= 5; ++i) { // 循环添加后续节点 cur->next = new ListNode(i); cur = cur->next; } cout << "递归方式输出:"; reversePrintRecursive(head); // 调用递归方法 cout << "\n栈方式输出:"; reversePrintStack(head); // 调用栈方法 // 内存释放(实际开发中需要) while (head) { ListNode* temp = head; head = head->next; delete temp; } return 0; } ``` ### 键实现说明 1. **递归方法**:利用函数调用栈实现逆序,递归链表末端后回溯时输出数据[^3] 2. **栈方法**:显式使用栈存储节点,通过先进后出特性实现逆序 3. **时间复杂度**:两种方式均为$O(n)$,需要完整遍历链表 4. **空间复杂度**:两种方式均为$O(n)$,递归使用隐式栈,显式栈使用额外内存 ### 主函数实现要点 1. 创建链表时采用动态内存分配 2. 使用循环结构添加节点 3. 同时演示两种方法的调用 4. 包含内存释放操作(实际开发必要)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值