输入一个链表,从尾到头打印链表每个节点的值。

输入描述:输入为链表的表头

输出描述:输出为需要打印的“新链表”的表头


一、问题分析


  初拿到这个题目时,这应该是考察单向链表这一数据结构。单向链表的遍历总是从头指针逐项遍历各个节点,现在要求从尾到头打印节点的值,我们可以在遍历时把各节点压入栈内,最后出栈打印各个节点值,即可达到要求。

  实现之前,我们先来看看如何创建一个链表。

  1,链表节点的数据结构定义

  1. 1 struct ListNode {
  2. 2 int val;
  3. 3 struct ListNode *next;
  4. 4 ListNode(int x) :
  5. 5 val(x), next(NULL) {
  6. 6 }
  7. 7 };

  在链表的定义中,包含自己的整形成员(当然也可以定义为其它数据类型,如double),以及下一个节点的位置信息(next)。这里我们还定义了节点的构造函数(ListNode),方便节点的初始化。

  2,链表的创建

  这里我们考虑单向链表。如果通过用户输入来创建链表,我们可以进行如下操作:

  1)创建头节点head,指向NULL。因为此时没有任何节点

  2)为加入的节点分配空间,赋初值(如1中考虑的int类型)并指向NULL。判断head==NULL?head指向该节点:“上一节点”指向该节点

  3)更新新加入的节点为“上一节点”

  4)判断节点是否添加结束,若否,重复2,3,4步骤继续添加节点。


二、问题的解决思路


  1,利用stack反转输出链表节点值

  1. #include <iostream>
  2. #include <vector>
  3. #include <stack>
  4. using namespace std;
  5.  
  6. //链表节点定义
  7. struct ListNode {
  8. int val;
  9. struct ListNode *next;
  10. ListNode(int x) :
  11. val(x), next(NULL) {
  12. }
  13. };
  14.  
  15. //链表从尾到头输出节点值方法实现
  16. class Solution {
  17. public:
  18. //方法1,通过stack 这个container来实现反转链表
  19. vector<int> printListFromTailToHead(struct ListNode* head) {
  20. vector<int> result;
  21. if(head == NULL)
  22. return result;
  23. stack<ListNode*> reverse;
  24. ListNode* node = head;
  25. while(node != NULL) {
  26. reverse.push(node);
  27. node = node->next;
  28. }
  29. while(!reverse.empty()) {
  30. node = reverse.top();
  31. result.push_back(node->val);
  32. reverse.pop();
  33. }
  34. return result;
  35. }
  36. //方法2,原地反转链表,不介入其它container
  37. //不断的使“下一个节点”指向“前一个”节点
  38. vector<int> printListFromTailToHead2(struct ListNode* head) {
  39. vector<int> vec;
  40. ListNode *buf = head;
  41. ListNode *pre = buf;
  42. if(head == NULL)
  43. return vec;
  44. while(head->next != NULL){
  45. buf = head->next;
  46. head->next = buf->next;
  47. buf->next = pre;
  48. pre = buf;
  49. }
  50. while(buf){
  51. vec.push_back(buf->val);
  52. buf = buf->next;
  53. }
  54. return vec;
  55. }
  56. };
  57.  
  58. struct ListNode* CreateListNode(struct ListNode* head) {
  59. struct ListNode *p1, *p2;
  60. int i = ;
  61. p1 = p2 = (struct ListNode*)malloc(sizeof(ListNode));
  62. cout << "Please input the 1st node, it's address is p1_addr = " << p1 << endl;
  63. cout << "And input -1 to quit.";
  64. cin >> (p1->val);
  65. p1->next = NULL;
  66.  
  67. while (p1->val != -) {
  68. if (NULL == head) {
  69. head = p1;
  70. }
  71. else
  72. p2->next = p1;
  73. p2 = p1;
  74. p1 = (struct ListNode*)malloc(sizeof(ListNode));
  75. ++i;
  76. cout << "Please input the " << i << " node," << "it's address is p" << i << "_addr = " << p1 <<endl;
  77. cin >> (p1->val);
  78. }
  79. free(p1);
  80. p2->next = NULL;
  81. p1 = NULL;
  82. cout << "End of creating ListNode." << endl;
  83. return head;
  84. }
  85.  
  86. int main () {
  87. std::vector<int> v;
  88. struct ListNode* head = NULL;
  89. head = CreateListNode(head);
  90.  
  91. Solution s;
  92. v = s.printListFromTailToHead2(head);
  93. for (int var : v) {
  94. cout << var << ' ';
  95. }
  96.  
  97. //测试节点的初始化,与本题无关
  98. struct ListNode myListNode();
  99. cout << myListNode.val << endl;
  100.  
  101. }

  上述程序在gcc version 6.1.0下编译通过。

  在上面的程序中,实现反转的方法有两个:

  1)利用stack先入后出的特性实现链表的反转

  2)不借用其它container,不断的使“后一个”节点指向“前一个节点”来原地反转链表。下面来谈谈原地反转链表

  2,原地反转链表

  我们看函数printListFromTailToHead2()。首先,我们先定义两个指针(buf, pre),并与head共同指向链表的头节点。然后,通过head->next遍历原始链表,并同时更新buf指向已经遍历到的节点(buf = head->next),而这期间head始终指向头节点。然后,更新head—>next指向buf的下一个节点(head->next = buf->next)。接着,通过buf->next = pre, 使buf指向前一个节点,紧接着更新pre,使其指向当前节点,以便下一轮更新。

  当head->next遍历完链表后,buf指向了原始链表最后一个节点,head->next的值变为了NULL。现在从buf开始遍历,即可反向遍历链表。

剑指offer——从尾到头打印链表节点的值的更多相关文章

  1. 剑指Offer 从尾到头打印链表

    题目描述 输入一个链表,从尾到头打印链表每个节点的值. 输入描述: 输入为链表的表头 输出描述: 输出为需要打印的“新链表”的表头 思路: 用容器vector,递归到最后一个元素,push_back到 ...

  2. 剑指Offer——从尾到头打印链表

    题目描述: 输入一个链表,从尾到头打印链表每个节点的值. 分析: 方法1:利用栈的性质,先从头到尾遍历链表每个节点的值存入栈中,最后一个一个出栈顺序便是从尾到头的. 方法2:直接从头到尾遍历链表存储节 ...

  3. 剑指offer —— 从尾到头打印链表

    1.问题:输入一个链表,从尾到头打印链表每个节点的值. /** * public class ListNode { * int val; * ListNode next = null; * * Lis ...

  4. 用js刷剑指offer(从尾到头打印链表)

    题目描述 输入一个链表,按链表从尾到头的顺序返回一个ArrayList. 牛客网链接 js代码 /*function ListNode(x){ this.val = x; this.next = nu ...

  5. 4、剑指offer——从尾到头打印链表java实现

    **题目描述** **输入一个链表,按链表从尾到头的顺序返回一个ArrayList.** 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M 思路:   1.如果链 ...

  6. [剑指Offer]6-从尾到头打印链表

    典型的后进先出,可以借助栈,也可以使用递归. 考虑到若链表过长递归可能造成函数调用栈溢出,所以使用栈更好. 注意stack无遍历操作,全部用push(),pop(),top()完成. 以下创建列表胡乱 ...

  7. 剑指Offer-3.从尾到头打印链表(C++/Java)

    题目: 输入一个链表,按链表从尾到头的顺序返回一个ArrayList. 分析: 很简单的一道题,其实也就是从尾到头打印链表,题目要求返回ArrayList,其实也就是一个数组. 可以将链表中的元素全部 ...

  8. 剑指Offer_6_从尾到头打印链表

    题目描述        输入应该链表的头节点 , 从尾到头反过来打印出每个节点的值.链表定义如下 : typedef struct ListNode { int m_nKey ; ListNode * ...

  9. 剑指offer--18.从尾到头打印链表

    递归,逐个加到后面 ------------------------------------------------------------------------------ 时间限制:1秒 空间限 ...

随机推荐

  1. Serializable接口的背后

    序列化是什么? 序列化就是将一个对象的状态(各个属性量)保存起来,然后在适当的时候再获得.序列化分为两大部分:序列化和反序列化. 序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网 ...

  2. JVM学习之强引用、弱引用、软引用、虚引用

    转自:http://my.oschina.net/ydsakyclguozi/blog/404389 多谢博主分享 1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象 ...

  3. STL MAP 反序迭代

    ITS_NOTICE_MAP::reverse_iterator it = noticeMap.rbegin(); for ( ; it != noticeMap.rend(); ++it ) { I ...

  4. Windows Server 2008防火墙问题及Sql Server2005用户登录问题

    一.Windows Server 2008防火墙问题 1.  问题: 1.在 Windows 安全中心中单击“立即打开”以打开 Windows 防火墙时,会收到以下错误消息:安全中心无法打开 Wind ...

  5. JS输出日历

    页面HTML代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> &l ...

  6. struts2笔记04-XxxAware接口

    1.XxxAware接口 ApplicationAware, RequestAware,SessionAware, ParameterAware.      struts2提供了这四个Aware接口用 ...

  7. Trafic

    Dialogue 1  You took the wrong bus 你做错车了 A:Hi, I want to see the Terra Cotta Warriors in Xi'an. Coul ...

  8. ORACLE视图添加备注

    ORACLE视图添加备注 版权声明:本文为博主原创文章,未经博主允许不得转载. create or replace view oes_material_series_ref as select t.p ...

  9. Cortex-M3学习日志(一)-- GPIO实验

    因为项目所需,所以不得不开始研究M3,我用的是NXP公司的LPC1768这个芯片,它是具有三级流水线的哈佛结构,带独立的本地指令和数据总线以及用于外设的稍微低性能的第三条总线,还包含一个支持随机跳转的 ...

  10. OAuth认证的过程

    在认证和授权的过程中涉及的三方包括:     服务提供方,用户使用服务提供方来存储受保护的资源,如照片,视频,联系人列表.     用户,存放在服务提供方的受保护的资源的拥有者.     客户端,要访 ...