(说明:本博客中的题目题目详细说明参考代码均摘自 “何海涛《剑指Offer:名企面试官精讲典型编程题》2012年”)

题目

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

进一步详细说明:
不允许在打印时修改链表的结构。链表结点可定义为:

  1. struct ListNode
  2. {
  3. int m_nKey;
  4. ListNode* m_pNext;
  5. };

算法设计思想

正常情况,遍历链表都是从前到后的,即从头到尾。如果从尾到头打印链表元素,可以借助栈的 “后入先出” (Last in, First out)的性质,在正向遍历时将链表元素依次压栈,当到达链表末尾时,再依次弹出并打印。

具体实现可以采用两种方法:迭代和递归。正如书中所说,“递归在本质上就是一个栈结构”。递归实现,从理论上,完全可以利用栈结构转换为非递归实现,即迭代方法。

C++ 实现

  1. #include <iostream>
  2. #include <stack>
  3.  
  4. struct ListNode
  5. {
  6. int m_nKey;
  7. ListNode* m_pNext;
  8. };
  9.  
  10. void AddToTail(ListNode** pHead, int value)
  11. {
  12. ListNode* pNew = new ListNode();
  13. pNew->m_nKey = value;
  14. pNew->m_pNext = NULL;
  15.  
  16. if (*pHead == NULL)
  17. {
  18. *pHead = pNew;
  19. }
  20. else
  21. {
  22. ListNode* pNode = *pHead;
  23. while (pNode->m_pNext != NULL)
  24. pNode = pNode->m_pNext;
  25. pNode->m_pNext = pNew;
  26. }
  27. }
  28.  
  29. void PrintLinkedList(const ListNode* head)
  30. {
  31. if (head == NULL) // 易漏点
  32. return;
  33.  
  34. ListNode* ptr = (ListNode*) head;
  35. while (ptr->m_pNext != NULL)
  36. {
  37. std::cout << ptr->m_nKey << " -> ";
  38. ptr = ptr->m_pNext;
  39. }
  40.  
  41. std::cout << ptr->m_nKey << std::endl;
  42. }
  43.  
  44. void DestroyLinkedList(ListNode** pHead)
  45. {
  46. if (pHead == NULL || *pHead == NULL) // 易漏点
  47. return;
  48.  
  49. ListNode* pNode = NULL;
  50. while (*pHead != NULL)
  51. {
  52. pNode = *pHead;
  53. *pHead = (*pHead)->m_pNext;
  54. delete pNode;
  55. }
  56. }
  57.  
  58. // Iterative method
  59. void PrintListReversingly_Iteratively(const ListNode* pHead)
  60. {
  61. if (pHead == NULL)
  62. return;
  63.  
  64. ListNode* pNode = (ListNode*) pHead;
  65. std::stack<ListNode*> nodes;
  66.  
  67. while (pNode != NULL)
  68. {
  69. nodes.push(pNode);
  70. pNode = pNode->m_pNext;
  71. }
  72.  
  73. while (!nodes.empty())
  74. {
  75. pNode = nodes.top();
  76. nodes.pop();
  77. std::cout << pNode->m_nKey << ", ";
  78. }
  79. std::cout << std::endl;
  80. }
  81.  
  82. // Recursive method
  83. void PrintListReversingly_Recursively(const ListNode* pHead)
  84. {
  85. if (pHead != NULL)
  86. {
  87. if (pHead->m_pNext != NULL)
  88. {
  89. PrintListReversingly_Recursively(pHead->m_pNext);
  90. }
  91.  
  92. std::cout << pHead->m_nKey << ", ";
  93. }
  94. }
  95.  
  96. void unitest()
  97. {
  98. ListNode* head = NULL;
  99.  
  100. AddToTail(&head, );
  101. AddToTail(&head, );
  102. AddToTail(&head, );
  103. AddToTail(&head, );
  104. AddToTail(&head, );
  105.  
  106. std::cout << "Print forward: ";
  107. PrintLinkedList(head);
  108. std::cout << "Print reversely iteratively: ";
  109. PrintListReversingly_Iteratively(head);
  110. std::cout << "Print reversely recursively: ";
  111. PrintListReversingly_Recursively(head);
  112.  
  113. // Release memory
  114. DestroyLinkedList(&head); // 易漏点
  115. }
  116.  
  117. int main()
  118. {
  119. unitest();
  120.  
  121. return ;
  122. }

Python 实现

  1. #!/usr/bin/python
  2. # -*- coding: utf8 -*-
  3.  
  4. from __future__ import print_function
  5.  
  6. class ListNode:
  7. def __init__(self, value, next_node=None):
  8. self.value = value
  9. self.next = next_node
  10.  
  11. def add_to_tail(head, value):
  12. q = ListNode(value)
  13.  
  14. if head is None:
  15. head = q
  16. else:
  17. p = head
  18. while p.next is not None:
  19. p = p.next
  20. p.next = q
  21.  
  22. return head
  23.  
  24. def print_list_reversely_iteratively(head):
  25. p = head
  26. stack = []
  27. # Push into stack
  28. while p is not None:
  29. stack.append(p.value)
  30. p = p.next
  31. # Pop from stack
  32. while stack:
  33. elem = stack.pop()
  34. print(elem, end=', ')
  35. print('')
  36.  
  37. def print_list_reversely_recursively(head):
  38. if head is None:
  39. return
  40. if head.next is not None:
  41. print_list_reversely_recursively(head.next)
  42. print(head.value, end=', ')
  43.  
  44. def print_linked_list_forward(head):
  45. if head is None:
  46. print("This linked list is empty!")
  47. return
  48.  
  49. p = head
  50. while p is not None:
  51. print(p.value, end='')
  52. if p.next is not None:
  53. print(' -> ', end='')
  54. p = p.next
  55. print('')
  56.  
  57. def unitest():
  58. linked_list = None
  59. linked_list = add_to_tail(linked_list, 1)
  60. linked_list = add_to_tail(linked_list, 2)
  61. linked_list = add_to_tail(linked_list, 3)
  62. linked_list = add_to_tail(linked_list, 5)
  63. linked_list = add_to_tail(linked_list, 4)
  64. print("Print forward: ", end='')
  65. print_linked_list_forward(linked_list)
  66. print("Print reversely iteratively: ", end='')
  67. print_list_reversely_iteratively(linked_list)
  68. print("Print reversely recursively: ", end='')
  69. print_list_reversely_recursively(linked_list)
  70.  
  71. if __name__ == '__main__':
  72. unitest()

注:使用 Python 利用函数建立链表时,需要注意函数参数的值传递和引用传递,此为易错点

参考代码

1. targetver.h (05_PrintListInReversedOrder/ 目录)

  1. #pragma once
  2.  
  3. // The following macros define the minimum required platform. The minimum required platform
  4. // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
  5. // your application. The macros work by enabling all features available on platform versions up to and
  6. // including the version specified.
  7.  
  8. // Modify the following defines if you have to target a platform prior to the ones specified below.
  9. // Refer to MSDN for the latest info on corresponding values for different platforms.
  10. #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
  11. #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
  12. #endif

2. stdafx.h (05_PrintListInReversedOrder/ 目录)

  1. // stdafx.h : include file for standard system include files,
  2. // or project specific include files that are used frequently, but
  3. // are changed infrequently
  4. //
  5.  
  6. #pragma once
  7.  
  8. #include "targetver.h"
  9.  
  10. #include <stdio.h>
  11. #include <tchar.h>
  12.  
  13. // TODO: reference additional headers your program requires here

3. stdafx.cpp (05_PrintListInReversedOrder/ 目录)

  1. // stdafx.cpp : source file that includes just the standard includes
  2. // PrintListInReversedOrder.pch will be the pre-compiled header
  3. // stdafx.obj will contain the pre-compiled type information
  4.  
  5. #include "stdafx.h"
  6.  
  7. // TODO: reference any additional headers you need in STDAFX.H
  8. // and not in this file

4. PrintListInReversedOrder.cpp

  1. // PrintListInReversedOrder.cpp : Defines the entry point for the console application.
  2. //
  3.  
  4. // 《剑指Offer——名企面试官精讲典型编程题》代码
  5. // 著作权所有者:何海涛
  6.  
  7. #include "stdafx.h"
  8. #include "..\Utilities\List.h"
  9. #include <stack>
  10.  
  11. void PrintListReversingly_Iteratively(ListNode* pHead)
  12. {
  13. std::stack<ListNode*> nodes;
  14.  
  15. ListNode* pNode = pHead;
  16. while(pNode != NULL)
  17. {
  18. nodes.push(pNode);
  19. pNode = pNode->m_pNext;
  20. }
  21.  
  22. while(!nodes.empty())
  23. {
  24. pNode = nodes.top();
  25. printf("%d\t", pNode->m_nValue);
  26. nodes.pop();
  27. }
  28. }
  29.  
  30. void PrintListReversingly_Recursively(ListNode* pHead)
  31. {
  32. if(pHead != NULL)
  33. {
  34. if (pHead->m_pNext != NULL)
  35. {
  36. PrintListReversingly_Recursively(pHead->m_pNext);
  37. }
  38.  
  39. printf("%d\t", pHead->m_nValue);
  40. }
  41. }
  42.  
  43. void Test(ListNode* pHead)
  44. {
  45. PrintList(pHead);
  46. PrintListReversingly_Iteratively(pHead);
  47. printf("\n");
  48. PrintListReversingly_Recursively(pHead);
  49. }
  50.  
  51. // 1->2->3->4->5
  52. void Test1()
  53. {
  54. printf("\nTest1 begins.\n");
  55.  
  56. ListNode* pNode1 = CreateListNode();
  57. ListNode* pNode2 = CreateListNode();
  58. ListNode* pNode3 = CreateListNode();
  59. ListNode* pNode4 = CreateListNode();
  60. ListNode* pNode5 = CreateListNode();
  61.  
  62. ConnectListNodes(pNode1, pNode2);
  63. ConnectListNodes(pNode2, pNode3);
  64. ConnectListNodes(pNode3, pNode4);
  65. ConnectListNodes(pNode4, pNode5);
  66.  
  67. Test(pNode1);
  68.  
  69. DestroyList(pNode1);
  70. }
  71.  
  72. // 只有一个结点的链表: 1
  73. void Test2()
  74. {
  75. printf("\nTest2 begins.\n");
  76.  
  77. ListNode* pNode1 = CreateListNode();
  78.  
  79. Test(pNode1);
  80.  
  81. DestroyList(pNode1);
  82. }
  83.  
  84. // 空链表
  85. void Test3()
  86. {
  87. printf("\nTest3 begins.\n");
  88.  
  89. Test(NULL);
  90. }
  91.  
  92. int _tmain(int argc, _TCHAR* argv[])
  93. {
  94. Test1();
  95. Test2();
  96. Test3();
  97.  
  98. return ;
  99. }

5. targetver.h (Utilities/ 目录)

  1. #pragma once
  2.  
  3. // The following macros define the minimum required platform. The minimum required platform
  4. // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
  5. // your application. The macros work by enabling all features available on platform versions up to and
  6. // including the version specified.
  7.  
  8. // Modify the following defines if you have to target a platform prior to the ones specified below.
  9. // Refer to MSDN for the latest info on corresponding values for different platforms.
  10. #ifndef WINVER // Specifies that the minimum required platform is Windows Vista.
  11. #define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows.
  12. #endif
  13.  
  14. #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
  15. #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
  16. #endif
  17.  
  18. #ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98.
  19. #define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
  20. #endif
  21.  
  22. #ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0.
  23. #define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE.
  24. #endif

6. stdafx.h (Utilities/ 目录)

  1. // stdafx.h : include file for standard system include files,
  2. // or project specific include files that are used frequently, but
  3. // are changed infrequently
  4. //
  5.  
  6. #pragma once
  7.  
  8. #include "targetver.h"
  9.  
  10. #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
  11. // Windows Header Files:
  12. #include <windows.h>
  13. #include <stdio.h>
  14.  
  15. // TODO: reference additional headers your program requires here

7. stdafx.cpp (Utilities/ 目录)

  1. // stdafx.cpp : source file that includes just the standard includes
  2. // Utilities.pch will be the pre-compiled header
  3. // stdafx.obj will contain the pre-compiled type information
  4.  
  5. #include "stdafx.h"
  6.  
  7. // TODO: reference any additional headers you need in STDAFX.H
  8. // and not in this file

8. List.h

  1. // 《剑指Offer——名企面试官精讲典型编程题》代码
  2. // 著作权所有者:何海涛
  3.  
  4. struct ListNode
  5. {
  6. int m_nValue;
  7. ListNode* m_pNext;
  8. };
  9.  
  10. __declspec( dllexport ) ListNode* CreateListNode(int value);
  11. __declspec( dllexport ) void ConnectListNodes(ListNode* pCurrent, ListNode* pNext);
  12. __declspec( dllexport ) void PrintListNode(ListNode* pNode);
  13. __declspec( dllexport ) void PrintList(ListNode* pHead);
  14. __declspec( dllexport ) void DestroyList(ListNode* pHead);
  15. __declspec( dllexport ) void AddToTail(ListNode** pHead, int value);
  16. __declspec( dllexport ) void RemoveNode(ListNode** pHead, int value);

9. List.cpp

  1. // Utilities.cpp : Defines the exported functions for the DLL application.
  2. //
  3.  
  4. // 《剑指Offer——名企面试官精讲典型编程题》代码
  5. // 著作权所有者:何海涛
  6.  
  7. #include "stdafx.h"
  8. #include "list.h"
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11.  
  12. ListNode* CreateListNode(int value)
  13. {
  14. ListNode* pNode = new ListNode();
  15. pNode->m_nValue = value;
  16. pNode->m_pNext = NULL;
  17.  
  18. return pNode;
  19. }
  20.  
  21. void ConnectListNodes(ListNode* pCurrent, ListNode* pNext)
  22. {
  23. if(pCurrent == NULL)
  24. {
  25. printf("Error to connect two nodes.\n");
  26. exit();
  27. }
  28.  
  29. pCurrent->m_pNext = pNext;
  30. }
  31.  
  32. void PrintListNode(ListNode* pNode)
  33. {
  34. if(pNode == NULL)
  35. {
  36. printf("The node is NULL\n");
  37. }
  38. else
  39. {
  40. printf("The key in node is %d.\n", pNode->m_nValue);
  41. }
  42. }
  43.  
  44. void PrintList(ListNode* pHead)
  45. {
  46. printf("PrintList starts.\n");
  47.  
  48. ListNode* pNode = pHead;
  49. while(pNode != NULL)
  50. {
  51. printf("%d\t", pNode->m_nValue);
  52. pNode = pNode->m_pNext;
  53. }
  54.  
  55. printf("\nPrintList ends.\n");
  56. }
  57.  
  58. void DestroyList(ListNode* pHead)
  59. {
  60. ListNode* pNode = pHead;
  61. while(pNode != NULL)
  62. {
  63. pHead = pHead->m_pNext;
  64. delete pNode;
  65. pNode = pHead;
  66. }
  67. }
  68.  
  69. void AddToTail(ListNode** pHead, int value)
  70. {
  71. ListNode* pNew = new ListNode();
  72. pNew->m_nValue = value;
  73. pNew->m_pNext = NULL;
  74.  
  75. if(*pHead == NULL)
  76. {
  77. *pHead = pNew;
  78. }
  79. else
  80. {
  81. ListNode* pNode = *pHead;
  82. while(pNode->m_pNext != NULL)
  83. pNode = pNode->m_pNext;
  84.  
  85. pNode->m_pNext = pNew;
  86. }
  87. }
  88.  
  89. void RemoveNode(ListNode** pHead, int value)
  90. {
  91. if(pHead == NULL || *pHead == NULL)
  92. return;
  93.  
  94. ListNode* pToBeDeleted = NULL;
  95. if((*pHead)->m_nValue == value)
  96. {
  97. pToBeDeleted = *pHead;
  98. *pHead = (*pHead)->m_pNext;
  99. }
  100. else
  101. {
  102. ListNode* pNode = *pHead;
  103. while(pNode->m_pNext != NULL && pNode->m_pNext->m_nValue != value)
  104. pNode = pNode->m_pNext;
  105.  
  106. if(pNode->m_pNext != NULL && pNode->m_pNext->m_nValue == value)
  107. {
  108. pToBeDeleted = pNode->m_pNext;
  109. pNode->m_pNext = pNode->m_pNext->m_pNext;
  110. }
  111. }
  112.  
  113. if(pToBeDeleted != NULL)
  114. {
  115. delete pToBeDeleted;
  116. pToBeDeleted = NULL;
  117. }
  118. }

10. 参考代码下载

项目 05_PrintListInReversedOrder 下载: 百度网盘

何海涛《剑指Offer:名企面试官精讲典型编程题》 所有参考代码下载:百度网盘

参考资料

[1]  何海涛. 剑指 Offer:名企面试官精讲典型编程题 [M]. 北京:电子工业出版社,2012. 49-53.

从尾到头打印链表(C++和Python 实现)的更多相关文章

  1. 【剑指Offer】06. 从尾到头打印链表 解题报告(Java & python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 解题方法 栈 递归 数组 日期 题目地址:https://leetcode ...

  2. 《剑指offer》从尾到头打印链表

    本题来自<剑指offer> 从尾到头打印链表 题目: 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. 思路: 方案一:首先遍历到尾部,然后从尾部进行到头值进行操作,后进先 ...

  3. 剑指Offer面试题:4.从尾到头打印链表

    一.题目:从尾到头打印链表 题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值. 到解决这个问题肯定要遍历链表.遍历的顺序是从头到尾的顺序,可输出的顺序却是从尾到头.也就是说第一个遍历到的结 ...

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

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

  5. offer--链表反转和从尾到头打印链表

    这个是高频的面试题,今天总结了一些.反转链表用三个指针实现,返回新链表的头节点:而从尾到头打印,应用栈实现,返回vector整个链表. //题目描述 // //输入一个链表,反转链表后,输出链表的所有 ...

  6. P51、面试题5:从尾到头打印链表

    题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值. 链表结点定义如下: Struct ListNode{ int   m_nKey; ListNode*   m_pNext; }; 我们可 ...

  7. 九度OJ 1511 从尾到头打印链表

    题目地址:http://ac.jobdu.com/problem.php?pid=1511 题目描述: 输入一个链表,从尾到头打印链表每个节点的值. 输入: 每个输入文件仅包含一组测试样例. 每一组测 ...

  8. 剑指offer——从尾到头打印链表节点的值

    输入一个链表,从尾到头打印链表每个节点的值. 输入描述:输入为链表的表头 输出描述:输出为需要打印的“新链表”的表头 一.问题分析 初拿到这个题目时,这应该是考察单向链表这一数据结构.单向链表的遍历总 ...

  9. 剑指offer【03】- 从尾到头打印链表(4种实现方法)

    题目:从尾到头打印链表 考点:链表 题目描述:输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. 法一:ArrayList头插法 /** * public class ListNode ...

随机推荐

  1. IE8 placeholder不支持的兼容性处理

    引入 <script type="text/javascript" src="<%=path%>/common/js/jquery/jquery.min ...

  2. 07-oracle多表查询

    --笛卡尔积,多表查询时,n张表中的行数相乘(本例中14*4=56)--多表查询时笛卡尔积无法消除,即使使用了限定条件(where)也只是不显示而已,实际上笛卡尔积仍存在 --只能使用合理的做法来处理 ...

  3. 《大数据日知录》读书笔记-ch2数据复制与一致性

    CAP理论:Consistency,Availability,Partition tolerance 对于一个分布式数据系统,CAP三要素不可兼得,至多实现其二.要么AP,要么CP,不存在CAP.分布 ...

  4. 判断title(title_is)

    判断 title 获取页面 title 的方法可以直接用 driver.title 获取到,然后也可以把获取到的结果用做断言.本篇介绍另外一种方法去判断页面 title 是否与期望结果一种,用到上一篇 ...

  5. javascript记住用户名和登录密码

    javascript记住用户名和登录密码 下面主要通过代码给大家展示下javascript记住用户名和登录密码,具体代码内容请看下文. <script type="text/javas ...

  6. JavaScript技巧45招(转)

    原文:45 Useful JavaScript Tips, Tricks and Best Practices作者:Saad Mousliki 在这篇文章里,我将分享一些JavaScript的技巧.秘 ...

  7. FocusBI: SSIS体系结构(原创)

    关注微信公众号:FocusBI 查看更多文章:加QQ群:808774277 获取学习资料和一起探讨问题. <商业智能教程>pdf下载地址 链接:https://pan.baidu.com/ ...

  8. html5的meta标签

    meta标签中的http-equiv属性使用介绍 meta是html语言head区的一个辅助性标签;meta标签的作用有:搜索引擎优化(SEO),定义页面使用语言等等;感兴趣的朋友可以了解下     ...

  9. LVS+keepalived DR模式配置高可用负载均衡集群

    实验环境 LVS-Master 10.0.100.201 VIP:10.0.100.203 LVS-Slave       10.0.100.204 WEB1-Tomcat 10.0.2.29 gat ...

  10. [APIO2018] Circle selection 选圆圈

    Description 给出 \(n\) 个圆 \((x_i,y_i,r_i)\) 每次重复以下步骤: 找出半径最大的圆,并删除与这个圆相交的圆 求出每一个圆是被哪个圆删除的 Solution \(k ...