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

题目

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

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

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

算法设计思想

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

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

C++ 实现

#include <iostream>
#include <stack> struct ListNode
{
int m_nKey;
ListNode* m_pNext;
}; void AddToTail(ListNode** pHead, int value)
{
ListNode* pNew = new ListNode();
pNew->m_nKey = value;
pNew->m_pNext = NULL; if (*pHead == NULL)
{
*pHead = pNew;
}
else
{
ListNode* pNode = *pHead;
while (pNode->m_pNext != NULL)
pNode = pNode->m_pNext;
pNode->m_pNext = pNew;
}
} void PrintLinkedList(const ListNode* head)
{
if (head == NULL) // 易漏点
return; ListNode* ptr = (ListNode*) head;
while (ptr->m_pNext != NULL)
{
std::cout << ptr->m_nKey << " -> ";
ptr = ptr->m_pNext;
} std::cout << ptr->m_nKey << std::endl;
} void DestroyLinkedList(ListNode** pHead)
{
if (pHead == NULL || *pHead == NULL) // 易漏点
return; ListNode* pNode = NULL;
while (*pHead != NULL)
{
pNode = *pHead;
*pHead = (*pHead)->m_pNext;
delete pNode;
}
} // Iterative method
void PrintListReversingly_Iteratively(const ListNode* pHead)
{
if (pHead == NULL)
return; ListNode* pNode = (ListNode*) pHead;
std::stack<ListNode*> nodes; while (pNode != NULL)
{
nodes.push(pNode);
pNode = pNode->m_pNext;
} while (!nodes.empty())
{
pNode = nodes.top();
nodes.pop();
std::cout << pNode->m_nKey << ", ";
}
std::cout << std::endl;
} // Recursive method
void PrintListReversingly_Recursively(const ListNode* pHead)
{
if (pHead != NULL)
{
if (pHead->m_pNext != NULL)
{
PrintListReversingly_Recursively(pHead->m_pNext);
} std::cout << pHead->m_nKey << ", ";
}
} void unitest()
{
ListNode* head = NULL; AddToTail(&head, );
AddToTail(&head, );
AddToTail(&head, );
AddToTail(&head, );
AddToTail(&head, ); std::cout << "Print forward: ";
PrintLinkedList(head);
std::cout << "Print reversely iteratively: ";
PrintListReversingly_Iteratively(head);
std::cout << "Print reversely recursively: ";
PrintListReversingly_Recursively(head); // Release memory
DestroyLinkedList(&head); // 易漏点
} int main()
{
unitest(); return ;
}

Python 实现

#!/usr/bin/python
# -*- coding: utf8 -*- from __future__ import print_function class ListNode:
def __init__(self, value, next_node=None):
self.value = value
self.next = next_node def add_to_tail(head, value):
q = ListNode(value) if head is None:
head = q
else:
p = head
while p.next is not None:
p = p.next
p.next = q return head def print_list_reversely_iteratively(head):
p = head
stack = []
# Push into stack
while p is not None:
stack.append(p.value)
p = p.next
# Pop from stack
while stack:
elem = stack.pop()
print(elem, end=', ')
print('') def print_list_reversely_recursively(head):
if head is None:
return
if head.next is not None:
print_list_reversely_recursively(head.next)
print(head.value, end=', ') def print_linked_list_forward(head):
if head is None:
print("This linked list is empty!")
return p = head
while p is not None:
print(p.value, end='')
if p.next is not None:
print(' -> ', end='')
p = p.next
print('') def unitest():
linked_list = None
linked_list = add_to_tail(linked_list, 1)
linked_list = add_to_tail(linked_list, 2)
linked_list = add_to_tail(linked_list, 3)
linked_list = add_to_tail(linked_list, 5)
linked_list = add_to_tail(linked_list, 4)
print("Print forward: ", end='')
print_linked_list_forward(linked_list)
print("Print reversely iteratively: ", end='')
print_list_reversely_iteratively(linked_list)
print("Print reversely recursively: ", end='')
print_list_reversely_recursively(linked_list) if __name__ == '__main__':
unitest()

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

参考代码

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

#pragma once

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

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

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
// #pragma once #include "targetver.h" #include <stdio.h>
#include <tchar.h> // TODO: reference additional headers your program requires here

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

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

4. PrintListInReversedOrder.cpp

// PrintListInReversedOrder.cpp : Defines the entry point for the console application.
// // 《剑指Offer——名企面试官精讲典型编程题》代码
// 著作权所有者:何海涛 #include "stdafx.h"
#include "..\Utilities\List.h"
#include <stack> void PrintListReversingly_Iteratively(ListNode* pHead)
{
std::stack<ListNode*> nodes; ListNode* pNode = pHead;
while(pNode != NULL)
{
nodes.push(pNode);
pNode = pNode->m_pNext;
} while(!nodes.empty())
{
pNode = nodes.top();
printf("%d\t", pNode->m_nValue);
nodes.pop();
}
} void PrintListReversingly_Recursively(ListNode* pHead)
{
if(pHead != NULL)
{
if (pHead->m_pNext != NULL)
{
PrintListReversingly_Recursively(pHead->m_pNext);
} printf("%d\t", pHead->m_nValue);
}
} 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();
ListNode* pNode2 = CreateListNode();
ListNode* pNode3 = CreateListNode();
ListNode* pNode4 = CreateListNode();
ListNode* pNode5 = CreateListNode(); ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode4, pNode5); Test(pNode1); DestroyList(pNode1);
} // 只有一个结点的链表: 1
void Test2()
{
printf("\nTest2 begins.\n"); ListNode* pNode1 = CreateListNode(); Test(pNode1); DestroyList(pNode1);
} // 空链表
void Test3()
{
printf("\nTest3 begins.\n"); Test(NULL);
} int _tmain(int argc, _TCHAR* argv[])
{
Test1();
Test2();
Test3(); return ;
}

5. targetver.h (Utilities/ 目录)

#pragma once

// The following macros define the minimum required platform.  The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
// your application. The macros work by enabling all features available on platform versions up to and
// including the version specified. // Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER // Specifies that the minimum required platform is Windows Vista.
#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif #ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98.
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
#endif #ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0.
#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE.
#endif

6. stdafx.h (Utilities/ 目录)

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
// #pragma once #include "targetver.h" #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
#include <stdio.h> // TODO: reference additional headers your program requires here

7. stdafx.cpp (Utilities/ 目录)

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

8. List.h

// 《剑指Offer——名企面试官精讲典型编程题》代码
// 著作权所有者:何海涛 struct ListNode
{
int m_nValue;
ListNode* m_pNext;
}; __declspec( dllexport ) ListNode* CreateListNode(int value);
__declspec( dllexport ) void ConnectListNodes(ListNode* pCurrent, ListNode* pNext);
__declspec( dllexport ) void PrintListNode(ListNode* pNode);
__declspec( dllexport ) void PrintList(ListNode* pHead);
__declspec( dllexport ) void DestroyList(ListNode* pHead);
__declspec( dllexport ) void AddToTail(ListNode** pHead, int value);
__declspec( dllexport ) void RemoveNode(ListNode** pHead, int value);

9. List.cpp

// Utilities.cpp : Defines the exported functions for the DLL application.
// // 《剑指Offer——名企面试官精讲典型编程题》代码
// 著作权所有者:何海涛 #include "stdafx.h"
#include "list.h"
#include <stdio.h>
#include <stdlib.h> ListNode* CreateListNode(int value)
{
ListNode* pNode = new ListNode();
pNode->m_nValue = value;
pNode->m_pNext = NULL; return pNode;
} void ConnectListNodes(ListNode* pCurrent, ListNode* pNext)
{
if(pCurrent == NULL)
{
printf("Error to connect two nodes.\n");
exit();
} pCurrent->m_pNext = pNext;
} void PrintListNode(ListNode* pNode)
{
if(pNode == NULL)
{
printf("The node is NULL\n");
}
else
{
printf("The key in node is %d.\n", pNode->m_nValue);
}
} void PrintList(ListNode* pHead)
{
printf("PrintList starts.\n"); ListNode* pNode = pHead;
while(pNode != NULL)
{
printf("%d\t", pNode->m_nValue);
pNode = pNode->m_pNext;
} printf("\nPrintList ends.\n");
} void DestroyList(ListNode* pHead)
{
ListNode* pNode = pHead;
while(pNode != NULL)
{
pHead = pHead->m_pNext;
delete pNode;
pNode = pHead;
}
} void AddToTail(ListNode** pHead, int value)
{
ListNode* pNew = new ListNode();
pNew->m_nValue = value;
pNew->m_pNext = NULL; 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)
{
if(pHead == NULL || *pHead == NULL)
return; ListNode* pToBeDeleted = NULL;
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->m_pNext; if(pNode->m_pNext != NULL && pNode->m_pNext->m_nValue == value)
{
pToBeDeleted = pNode->m_pNext;
pNode->m_pNext = pNode->m_pNext->m_pNext;
}
} if(pToBeDeleted != NULL)
{
delete pToBeDeleted;
pToBeDeleted = NULL;
}
}

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. 20190430-PPK大佬的三个Viewport

    写在前面的乱七八糟:在知识的海洋里狗刨,越刨会越自我膨胀,膨胀过后的自己,又会发现自己的渺小~ 目录 1.viewport 2.css的1px 3.三个viewport 参考文献: https://b ...

  2. J15W-J45W黄铜截止阀厂家,J15W-J45W黄铜截止阀价格 - 专题栏目 - 无极资讯网

    无极资讯网 首页 最新资讯 最新图集 最新标签   搜索 J15W-J45W黄铜截止阀 无极资讯网精心为您挑选了(J15W-J45W黄铜截止阀)信息,其中包含了(J15W-J45W黄铜截止阀)厂家,( ...

  3. 实习没事干之自学redis

    什么是Redis--http://how2j.cn/frontroute Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语 ...

  4. 修改eclipse下tomcat的内存大小/解决内存溢出

    我们安装完成eclipse之后,在我们的安装目录下有一个名为eclipse.ini文件. 打开文件里面的内容如下: -startup plugins/org.eclipse.equinox.launc ...

  5. Mysql远程连接配置

    Mysql远程连接配置 环境:unbuntu 16.04 最新版本的Mysql在远程连接的配置上与老版本有了一些出入,照原先的配置已经不行了,所以在这里记录一下遇到的所有新问题. 配置远程连接的步骤如 ...

  6. 1.8 js基础(常用方法小结)

    1.获取随机数 var rdm=function(n,m){ return parseInt(n+Math.random()*(m-n)); } 2.位数不够补0 function toDou(inu ...

  7. 跨平台 GUI可视化 网络调试工具

    mNetAssisthttp://blog.chinaunix.net/uid-21977056-id-4310527.htmlhttps://github.com/busyluo/mNetAssis ...

  8. java 并发(三)---Thread 线程

    Thread 的状态 线程共有五种状态.分别是: (1)新建 (2)就绪 (3)运行 (4)阻塞 (5)死亡 ,下面列列举的状态需要结合状态示意图更好理解.  新建状态(New): 新创建了一个线程对 ...

  9. C#在不同平台下DLL的引用问题

    缘起 很多时候,我们需要引用在不同平台下的DLL,32位(X86)和64位(X64).如果平台错误,在C#中会引发BadImageFormatException异常. 解决思路 我们同时不能添加不同平 ...

  10. html/JS onload的详解

    等待页面都加载完后再执行 <!DOCTYPE html><html lang="en"><head> <meta charset=&quo ...