剑指offer-05:从尾到头打印链表

输入一个链表的头结点,从尾到头反过来打印每个结点的值

首先复习下链表的基础:

struct ListNode
{
    int m_value;
    ListNode * p_next;
};

《数据结构》书上搞了头结点,即new了一个数值为空的结点,指向首结点。

而下面代码直接从首结点(左)开始。

开始还有些纠结,后来想明白了无论哪种都是可以的,只要搞清楚道理,操作正确即可。实践发现,搞个头结点还是好些:有些操作就是统一的,否则要考虑首结点和后面结点分开处理。

这里写图片描述

// 插入结点
void AddToTail(ListNode ** pHead, int value)
{
    ListNode * pNew = new ListNode();
    pNew->m_value = value;
    pNew->p_next = nullptr;

    if (*pHead == nullptr)
        *pHead = pNew;
    else
    {
        ListNode * pNode = *pHead;
        while (pNode->p_next != nullptr)
        {
            pNode = pNode->p_next;
        }
        pNode->p_next = pNew;
    }
}

插入时,先申请空间搞个新结点。然后看如果表还未建,则该结点为首结点,p指向首结点。若已建,则找到尾部,修改null指向新结点。

void Delete(ListNode ** pHead, int value)
{
    if (pHead == nullptr || *pHead == nullptr)
        return;
    // 如果是第一个结点,*pHead指向第二结点
    ListNode * pToDelete = *pHead;
    if (pToDelete->m_value == value)
    {
        *pHead = (*pHead)->p_next;
    }
    // 不是第一个则迭代往后找
    else 
    {
        while (pToDelete->p_next != nullptr && pToDelete->p_next->m_value != value)
        {
            pToDelete = pToDelete->p_next;
        }
        // 找到了该结点
        if (pToDelete->p_next != nullptr && pToDelete->p_next->m_value == value)
        {
            ListNode * ptmp = pToDelete;
            pToDelete = pToDelete->p_next;
            ptmp->p_next = ptmp->p_next->p_next;
        }
        // 没找到返回
        else
        {
            cout << "no this value" << endl;
            return;
        }
    }
    // 此处肯定是找到可删
    delete pToDelete;
    pToDelete = nullptr;
}

// 测试输出
int main()
{
    ListNode * List = nullptr;
    AddToTail(&List, 3); // 3
    AddToTail(&List, 4); // 3 -> 4
    AddToTail(&List, 5); // 3 -> 4 -> 5

    ListNode * pNode = List;
    while (pNode != nullptr)
    {
        cout << pNode->m_value;
        pNode = pNode->p_next;
    }

    Delete(&List, 5);

    pNode = List;
    while (pNode != nullptr)
    {
        cout << pNode->m_value;
        pNode = pNode->p_next;
    }

    return 0;
}

再来看本题目:实现结点逆序输出。

  • 思路1:遍历结点压栈,栈输出
  • 思路2:递归输出后面结点,再输出该结点本身
// 遍历结点压栈
void printReverseStack(ListNode * p)
{
    stack<ListNode *> nodes; // #include <stack>
    while (p != nullptr)
    {
        nodes.push(p);
        p = p->p_next;
    }
    while (!nodes.empty())
    {
        p = nodes.top();
        cout << p->m_value << "->";
        nodes.pop();
    }
}
// 递归打印输出
void printReverseRecursive(ListNode * p)
{
    if (p != nullptr)
    {
        // 当尾结点时返回
        if (p->p_next != nullptr)
            printReverseRecursive(p->p_next);
        // 打印子序列的第一个结点
        cout << p->m_value << "->";
    }
}

// 测试输出
ListNode * pNode = List;
printReverseStack(pNode);
printReverseRecursive(pNode);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值