您的位置:首页 > 编程语言 > C语言/C++

从尾到头打印链表(C++和Python 实现)

2017-09-26 08:31 519 查看
(说明:本博客中的题目题目详细说明参考代码均摘自 “何海涛《剑指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, 1);
AddToTail(&head, 2);
AddToTail(&head, 3);
AddToTail(&head, 5);
AddToTail(&head, 4);

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 0;
}


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/ 目录)

// 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(1);
}

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;
}
}


View Code
10. 参考代码下载

项目 05_PrintListInReversedOrder 下载: 百度网盘

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

参考资料

[1] 何海涛. 剑指 Offer:名企面试官精讲典型编程题 [M]. 北京:电子工业出版社,2012. 49-53.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: