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

文件main.cpp

// 从尾到头打印链表
// 题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。

#include <iostream>
#include <stack>
#include "List.h"
using namespace std;

void PrintListReversingly_Iteratively(ListNode* pHead)//解法一:使用栈
{
    stack<ListNode*> nodes;//定义一个类型为ListNode*的栈,其名为nodes

    ListNode* pNode = pHead;
    while (pNode != NULL)//压入栈
    {
        nodes.push(pNode);//在栈顶上堆进一个元素
        pNode = pNode->m_pNext;
    }

    while (!nodes.empty())//弹出栈并打印
    {
        pNode = nodes.top();//返回栈顶的元素,并不会删除
        cout << pNode->m_nValue<<"\t";
        nodes.pop();//删除掉栈顶上的元素
    }
}

void PrintListReversingly_Recursively(ListNode* pHead)//解法二:递归。但是容易因为链表过大而栈溢出
{
    if (pHead != NULL)
    {
        if (pHead->m_pNext != NULL)
        {
            PrintListReversingly_Recursively(pHead->m_pNext);
        }

        cout << pHead->m_nValue << "\t";
    }
}

// ====================测试代码====================
void Test(ListNode* pHead)
{
    PrintList(pHead);
    PrintListReversingly_Iteratively(pHead);
    printf("\n");
    PrintListReversingly_Recursively(pHead);
}

// 1->2->3->4->5
void Test1()
{
    printf("\nTest1 begins.\n");

    ListNode* pNode1 = CreateListNode(1);
    ListNode* pNode2 = CreateListNode(2);
    ListNode* pNode3 = CreateListNode(3);
    ListNode* pNode4 = CreateListNode(4);
    ListNode* pNode5 = CreateListNode(5);

    ConnectListNodes(pNode1, pNode2);
    ConnectListNodes(pNode2, pNode3);
    ConnectListNodes(pNode3, pNode4);
    ConnectListNodes(pNode4, pNode5);
    //也可以如下建立链表
    /*AddToTail(&pNode1, 2);
    AddToTail(&pNode1, 3);
    AddToTail(&pNode1, 4);
    AddToTail(&pNode1, 5);*/
    Test(pNode1);

    DestroyList(pNode1);
}

// 只有一个结点的链表: 1
void Test2()
{
    printf("\nTest2 begins.\n");

    ListNode* pNode1 = CreateListNode(1);

    Test(pNode1);

    DestroyList(pNode1);
}

// 空链表
void Test3()
{
    printf("\nTest3 begins.\n");

    Test(NULL);
}

int main()
{
    Test1();
    Test2();
    Test3();

    system("pause");
}

文件List.h

#ifndef LIST_H
#define LIST_H

struct ListNode
{
    int       m_nValue;
    ListNode* m_pNext;
};

ListNode* CreateListNode(int value);
void ConnectListNodes(ListNode* pCurrent, ListNode* pNext);
void PrintListNode(ListNode* pNode);
void PrintList(ListNode* pHead);
void DestroyList(ListNode* pHead);
void AddToTail(ListNode** pHead, int value);
void RemoveNode(ListNode** pHead, int value);

#endif

文件List.cpp

#include <iostream>
#include "List.h"
using namespace std;

ListNode* CreateListNode(int value)//创建一个节点,返回地址
{
    ListNode* pNode = new ListNode();//第一步:创建
    pNode->m_nValue = value;//第二步:给数据赋值
    pNode->m_pNext = NULL;//第三步:给下个节点地址附上NULL

    return pNode;
}

void ConnectListNodes(ListNode* pCurrent, ListNode* pNext)//将两个节点连接起来
{
    if (pCurrent == NULL)//第一步:判断当前节点存在否
    {
        cout << "Error to connect two nodes.\n";
        exit(1);//告诉系统,正常退出,结束进程
    }

    pCurrent->m_pNext = pNext;//第二步:将下一节点地址赋给当前节点的m_pNext
}

void PrintListNode(ListNode* pNode)//打印当前节点的数值
{
    if (pNode == NULL)//第一步:判断当前节点存在否
    {
        printf("The node is NULL.\n");
    }
    else
    {
        cout << "The key in node is %d.\n" << pNode->m_nValue;//第二步:打印
    }
}

void PrintList(ListNode* pHead)//打印整个链表的数值
{
    printf("PrintList starts.\n");

    ListNode* pNode = pHead;//第一步:建立一个pNode
    while (pNode != NULL)//第二步:检查当前节点为NULL不
    {
        cout << pNode->m_nValue << "\t";//第三步:不为空就打印
        pNode = pNode->m_pNext;//第四步:当前节点打印完,就把下一节点地址给pNode
    }

    printf("\nPrintList ends.\n");
}

void DestroyList(ListNode* pHead)//删除整个链表
{
    ListNode* pNode = pHead;//第一步:建立一个pNode
    while (pNode != NULL)//第二步:检查当前节点为NULL不
    {
        pHead = pHead->m_pNext;//第三步:不为空,头结点后移
        delete pNode;//第四步:删除结点pNode
        pNode = pHead;//第五步:头结点赋给pNode
    }
}

void AddToTail(ListNode** pHead, int value)//在链表最后添加节点,注意这里头结点一定是指向指针的指针
{
    ListNode* pNew = CreateListNode(value);//第一步:建立一个新节点

    if (*pHead == NULL)//第二步:若头结点为空,即空链表,就直接复制新节点就行了
    {
        *pHead = pNew;//这里是为什么 头结点一定是指向指针的指针 的关键,如果不是,出了这个函数,头结点会还是空的
    }

    else
    {
        ListNode* pNode = *pHead;//第三步:找到链表末尾
        while (pNode->m_pNext != NULL)
            pNode = pNode->m_pNext;

        pNode->m_pNext = pNew;//第四步:插入末尾
    }
}

void RemoveNode(ListNode** pHead, int value)//移除值为value的节点,这里头结点一定是指向指针的指针
{
    if (pHead == NULL || *pHead == NULL)//第一步:检查头指针和头结点存在不
        return;

    ListNode* pToBeDeleted = NULL;//第二步:创建一个节点pToBeDeleted留着被删除时候用
    if ((*pHead)->m_nValue == value)//第三步:先检查头结点,这个特殊
    {
        pToBeDeleted = *pHead;
        *pHead = (*pHead)->m_pNext;
    }
    else
    {
        ListNode* pNode = *pHead;
        while (pNode->m_pNext != NULL && pNode->m_pNext->m_nValue != value)//第四步:头结点没事,那就建立一个pNode向下找,注意判断条件
            pNode = pNode->m_pNext;//是确认pNode的下个节点不为空,且下个节点的值不是value,pNode才往下走

        if (pNode->m_pNext != NULL && pNode->m_pNext->m_nValue == value)//第五步:若下个节点的值是value,将下个节点赋给待删除节点pToBeDeleted,且将pNode的下下个节点地址赋给pNode的m_pNext
        {
            pToBeDeleted = pNode->m_pNext;
            pNode->m_pNext = pNode->m_pNext->m_pNext;
        }
    }

    if (pToBeDeleted != NULL)//第六步:删除节点pToBeDeleted
    {
        delete pToBeDeleted;
        pToBeDeleted = NULL;
    }
}

原文地址:https://www.cnblogs.com/CJT-blog/p/10465919.html

时间: 2024-10-15 08:19:32

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

剑指Offer_编程题_从尾到头打印链表

题目描述 输入一个链表,按链表从尾到头的顺序返回一个ArrayList. 创建链表相关,头插法和尾插法 关于头插法,可以next可以理解成前一个节点地址,插入顺序: 1.头节点传入,开始创建A数据,头节点的next指向A数据的内存地址,A节点的next替换成头节点的 2.头节点再传入,创建B数据,头节点的next又换成了指向B的内存地址,B节点的next替换头节点的A: 总结一下:插入时候,一直在头节点的上面插入数据,原来的数据被“顶”上去了: 头插法遍历的时候,头节点开始,一个一个往上遍历.这

刷题6 从尾到头打印链表

描述:  输入一个链表,从尾到头打印链表每个节点的值. 最初思路: 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* he

《剑指offer》刷题目录

<剑指offer>刷题目录 面试题03. 数组中重复的数字 面试题04. 二维数组中的查找 面试题05. 替换空格 面试题06. 从尾到头打印链表 面试题07. 重建二叉树 原文地址:https://www.cnblogs.com/qujingtongxiao/p/12652970.html

剑指Offer系列之题11~题15

目录 11.矩形覆盖 12.二进制中1的个数 13. 数值的整数次方 14.调整数组顺序使奇数位于偶数前面 15.链表中倒数第k个结点 11.矩形覆盖 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 比如n=3时,2*3的矩形块有3种覆盖方法: 斐波那契数列的应用 第一次竖着放一块类比为走一步,第一次横着放两块类比为走两步 代码与上面的斐波那契数列类题目类似,此处不再赘述:剑指Offer系列之题6~题10. 12.

剑指offer | 从尾到头打印链表

题目描述: “输入一个链表,从尾到头打印链表每个节点的值.” 这是我做的<剑指offer>系列的第一题,好的开头就是成功的一半.然而,我提交了一次,WA!再提交,WA!Com'on! 看来我的开端并不顺利.不过我要的可不是成功的一半,这样的开端怎么能阻挡我AC之路!仔细看了一遍题目要求,看了提交格式.再提交! Finally,AC! 代码如下: 1 /** 2 * struct ListNode { 3 * int val; 4 * struct ListNode *next; 5 * Lis

【剑指offer】Q5:从尾到头打印链表

可以练习下链表的逆置. def PrintListReversingly(head): if head == None: return if head: PrintListReversingly(head.next) print head.val def reverse(head): if head == None or head.next == None: return head psuhead = ListNode(-1) while head: nexthead = head.next h

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 typedef struct ListNode 2 { 3 int value; 4 ListNode *next; 5 }TListNode; 众所周知,链表打印时从头到尾很简单,所以我们首先想到的可能是先把链表逆序,然后从头到尾再打印出来即可,但是逆序会破坏链表的结构,对于打印操作来说仅仅是读操作而已,如果破坏了链表结构似乎不和常理,哪么我们是否有更好的解决办法呢?答案是肯定的. 我们知道要解决该问题肯定需要遍历链表,而第一个遍历的节点需要最后一个打印出来,而最后一个

题目五:从尾到头打印链表

////////////////////////////////////////////////////////////////////////////////////////////// // 8.题目五:从尾到头打印链表 // 方法一:时间复杂度O(n),空间复杂度O(n) template <typename TYPE> void ReversePrintList1(ListNode<TYPE>* pNode) { assert(NULL != pNode); stack&l