剑指offer(c++)-04.从尾到头打印链表

从尾到头打印链表

1. 前景知识

链表应该是面试时被提及最频繁的数据结构。链表的结构很简单,它由指针把若干个结点连接成链状结构。链表的创建、插入结点、删除结点等操作都只需要20行左右的代码就能实现,其代码量比较适合面试。

链表是一种动态数据结构,是因为在创建链表时,无须知道链表的长度。当插入一个结点时,只需要为新结点分配内存,然后调整指针的指向来确保新结点被链接到链表当中。内存分配不是在创建链表时一次性完成,而是每添加一个结点分配一次内存。由于没有闲置的内存,链表的空间效率比数组高。

由于链表中的内存不是一次性分配的,因而我们无法保证链表的内存和数组一样是连续的。因此如果想在链表中找到它的第i个结点,我们只能从头结点开始,沿着指向下一个结点的指针遍历链表,它的时间效率为O(n)。而在数组中,我们可以根据下标在O(1)时间内找到第i个元素。。

2. 链表相关题目(摘自:剑指offer):

面试题5:“从尾到头输出链表”、
面试题13:“在O(1)时间删除链表结点”、
面试题15:“链表中的倒数第k个结点”、
面试题16:“反转链表”、
面试题17:“合并两个排序的链表”、
面试题 37:“两个链表的第一个公共结点”等)
面试题26:“复杂链表的复制”,链表中的结点中除了有指向下一个结点的指针,还有指向任意结点的指针,这就是复杂链表。
面试题27:“二叉搜索树与双向链表”,链表中的结点中除了有指向下一个结点的指针,还有指向前一个结点的指针。这就是双向链表。
面试题45:“圆圈中最后剩下的数字”,把链表的末尾结点的指针指向头结点,从而形成一个环形链表。

3. 题目

面试题5 从尾到头打印链表: 输入一个链表的头结点,从尾到头反过来打印出每个结点的值。链表信息如下:

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/ 
4. 解题方法

解题思想1-递归思想

  1. 递归思想需要明确:递和归
  2. 递:下一结点即 head->next,
  3. 递结束判断条件:if( head == NULL ) return outvalue
  4. 归:返回该节点值即head->val
  5. 建立vector存储返回结点的val,并在每次递归调用后返回该值即return outvalue。
// 递归算法代码如下:
// head: 输入链表头
// outvalue: 返回链表值
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> outvalue;
        if(head == NULL)
            return outvalue;
        outvalue = printListFromTailToHead(head ->next);
        outvalue.push_back(head->val);
        return outvalue;
    }
};

解题思想2-反转链表

  1. 反转链表示例:输入: 1->2->3->4->5->NULL,输出: 5->4->3->2->1->NULL
  2. 需要三个结点变量,1.当前待反转结点tmp,2.正在反转的结点now,3.正在反转结点的前一个结点pre
  3. now = head ,tmp = now->next,now->next = pre,pre = now,now = tmp。 反转链表如图
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        // nullptr:c++11中关键字表示空指针
        ListNode* pre = nullptr; // pre:正在反转结点的前一个结点
        ListNode* now = head;    // now:当前正在反转的结点
        ListNode* tmp = now;     // tmp:还未反转的第一个结点
        while(now){
            tmp = now->next;
            now->next = pre;
            pre = now;
            now = tmp;
        }
        vector<int> outvalue;
        // 正序遍历单链表,将值压入vector,然后输出
        while(pre){
            outvalue.push_back(pre->val);
            pre = pre->next;
        }
        return outvalue;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值