《剑指offer》第六题(重要!从尾到头打印链表)
文件main.cpp
// 从尾到头打印链表
// 题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。 #include <iostream>
#include <stack>
#include "List.h"
using namespace std; void PrintListReversingly_Iteratively(ListNode* pHead)//解法一:使用栈
{
stack<ListNode*> nodes;//定义一个类型为ListNode*的栈,其名为nodes ListNode* pNode = pHead;
while (pNode != NULL)//压入栈
{
nodes.push(pNode);//在栈顶上堆进一个元素
pNode = pNode->m_pNext;
} while (!nodes.empty())//弹出栈并打印
{
pNode = nodes.top();//返回栈顶的元素,并不会删除
cout << pNode->m_nValue<<"\t";
nodes.pop();//删除掉栈顶上的元素
}
} void PrintListReversingly_Recursively(ListNode* pHead)//解法二:递归。但是容易因为链表过大而栈溢出
{
if (pHead != NULL)
{
if (pHead->m_pNext != NULL)
{
PrintListReversingly_Recursively(pHead->m_pNext);
} cout << pHead->m_nValue << "\t";
}
} // ====================测试代码====================
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);
//也可以如下建立链表
/*AddToTail(&pNode1, 2);
AddToTail(&pNode1, 3);
AddToTail(&pNode1, 4);
AddToTail(&pNode1, 5);*/
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 main()
{
Test1();
Test2();
Test3(); system("pause");
}
文件List.h
#ifndef LIST_H
#define LIST_H struct ListNode
{
int m_nValue;
ListNode* m_pNext;
}; ListNode* CreateListNode(int value);
void ConnectListNodes(ListNode* pCurrent, ListNode* pNext);
void PrintListNode(ListNode* pNode);
void PrintList(ListNode* pHead);
void DestroyList(ListNode* pHead);
void AddToTail(ListNode** pHead, int value);
void RemoveNode(ListNode** pHead, int value); #endif
文件List.cpp
#include <iostream>
#include "List.h"
using namespace std; ListNode* CreateListNode(int value)//创建一个节点,返回地址
{
ListNode* pNode = new ListNode();//第一步:创建
pNode->m_nValue = value;//第二步:给数据赋值
pNode->m_pNext = NULL;//第三步:给下个节点地址附上NULL return pNode;
} void ConnectListNodes(ListNode* pCurrent, ListNode* pNext)//将两个节点连接起来
{
if (pCurrent == NULL)//第一步:判断当前节点存在否
{
cout << "Error to connect two nodes.\n";
exit();//告诉系统,正常退出,结束进程
} pCurrent->m_pNext = pNext;//第二步:将下一节点地址赋给当前节点的m_pNext
} void PrintListNode(ListNode* pNode)//打印当前节点的数值
{
if (pNode == NULL)//第一步:判断当前节点存在否
{
printf("The node is NULL.\n");
}
else
{
cout << "The key in node is " << pNode->m_nValue <<endl;//第二步:打印
}
} void PrintList(ListNode* pHead)//打印整个链表的数值
{
printf("PrintList starts.\n"); ListNode* pNode = pHead;//第一步:建立一个pNode
while (pNode != NULL)//第二步:检查当前节点为NULL不
{
cout << pNode->m_nValue << "\t";//第三步:不为空就打印
pNode = pNode->m_pNext;//第四步:当前节点打印完,就把下一节点地址给pNode
} printf("\nPrintList ends.\n");
} void DestroyList(ListNode* pHead)//删除整个链表
{
ListNode* pNode = pHead;//第一步:建立一个pNode
while (pNode != NULL)//第二步:检查当前节点为NULL不
{
pHead = pHead->m_pNext;//第三步:不为空,头结点后移
delete pNode;//第四步:删除结点pNode
pNode = pHead;//第五步:头结点赋给pNode
}
} void AddToTail(ListNode** pHead, int value)//在链表最后添加节点,注意这里头结点一定是指向指针的指针
{
ListNode* pNew = CreateListNode(value);//第一步:建立一个新节点 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)//移除值为value的节点,这里头结点一定是指向指针的指针
{
if (pHead == NULL || *pHead == NULL)//第一步:检查头指针和头结点存在不
return; ListNode* pToBeDeleted = NULL;//第二步:创建一个节点pToBeDeleted留着被删除时候用
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 = pNode->m_pNext;//是确认pNode的下个节点不为空,且下个节点的值不是value,pNode才往下走 if (pNode->m_pNext != NULL && pNode->m_pNext->m_nValue == value)//第五步:若下个节点的值是value,将下个节点赋给待删除节点pToBeDeleted,且将pNode的下下个节点地址赋给pNode的m_pNext
{
pToBeDeleted = pNode->m_pNext;
pNode->m_pNext = pNode->m_pNext->m_pNext;
}
} if (pToBeDeleted != NULL)//第六步:删除节点pToBeDeleted
{
delete pToBeDeleted;
pToBeDeleted = NULL;
}
}
《剑指offer》第六题(重要!从尾到头打印链表)的更多相关文章
- 剑指offer第3题:从尾到头打印链表
方法一:采用栈来存储,用ArrayList保存.注意题目给出的输出结果是ArrayList import java.util.ArrayList; import java.util.Stack; pu ...
- C++版 - 剑指offer 面试题5:从尾到头打印链表 题解
面试题5:从尾到头打印链表 提交网址: http://www.nowcoder.com/practice/d0267f7f55b3412ba93bd35cfa8e8035?tpId=13&tq ...
- 剑指Offer:面试题5——从尾到头打印链表(java实现)
问题描述:输入一个链表的头结点,从尾巴到头反过来打印出每个结点的值. 首先定义链表结点 public class ListNode { int val; ListNode next = null; L ...
- 剑指Offer(三):从尾到头打印链表
一.前言 刷题平台:牛客网 二.题目 输入一个链表,返回一个反序的链表. 1.思路 通常,这种情况下,我们不希望修改原链表的结构.返回一个反序的链表,这就是经典的"后进先出",我们 ...
- 剑指Offer面试题:4.从尾到头打印链表
一.题目:从尾到头打印链表 题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值. 到解决这个问题肯定要遍历链表.遍历的顺序是从头到尾的顺序,可输出的顺序却是从尾到头.也就是说第一个遍历到的结 ...
- 剑指offer——面试题6:从尾到头打印链表
#include"iostream" #include"stdio.h" #include"stack" using namespace s ...
- 剑指offer 面试题5 : 从尾到头打印链表
题目: 输入一个链表的头结点,从尾到头反过来打印出每个节点的值.链表结点定义如下: struct ListNode { int m_nKey; ListNode* m_pNext; }; 思路: 通常 ...
- 《剑指offer》面试题5—从尾到头打印链表
重要思路: 这个问题肯定要遍历链表,遍历链表的顺序是从头到尾,而要输出的顺序却是从尾到头,典型的“后进先出”,可以用栈实现. 注意stl栈的使用,遍历stack的方法. #include <io ...
- 剑指Offer(书):从尾到头打印链表
题目:输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. 分析:若不允许修改原链表的值,则可以使用栈来实现,也可以使用另外一个ArrayList做中转的数据. public ArrayL ...
- 【剑指offer】面试题 6. 从尾到头打印链表
面试题 6. 从尾到头打印链表 NowCoder 题目描述 输入一个链表的头结点,从尾到头反过来打印出每个结点的值. Java 实现 ListNode Class class ListNode { i ...
随机推荐
- Java之构造器和构造方法的使用和意义
我总是要把构造器和方法混淆,后来发现, 方法,实际上,是需要用于执行java代码的,而构造器, 构造器,,,是一个类的实例!!(我的理解,构造器是一个对象) 为什么呢? 类的实例,我们需要用类来创建对 ...
- cmd重启服务器,有时不想去机房,并且远程桌面连接登录不上了
有时不想去机房,并且远程桌面连接登录不上了,需要远程重启服务器的,这时可以使用命令行方式远程重启.在cmd命令行状态下输入:shutdown -r -m \\192.168.1.10 -t 0 -f ...
- Spring Security中异常上抛机制及对于转型处理的一些感悟
在使用Spring Security的过程中,我们会发现框架内部按照错误及问题出现的场景,划分出了许许多多的异常,但是在业务调用时一般都会向外抛一个统一的异常出来,为什么要这样做呢,以及对于抛出来的异 ...
- 安全测试===sqlmap(壹)转载
六.优化 这些参数可以优化Sqlmap的性能. 1.一键优化 参数:-o 添加此参数相当于同时添加下列三个优化参数: --keep-alive --null-connection --threads= ...
- 【Python】Python 网页爬虫 & 文本处理 & 科学计算 & 机器学习 & 数据挖掘兵器谱
本文转载自:https://www.cnblogs.com/colipso/p/4284510.html 好文 mark http://www.52nlp.cn/python-%E7%BD%91%E9 ...
- linux常用命令:whereis 命令
whereis命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b).man说明文件(参数-m)和源代码文件(参数-s).如果省略参数,则返回所有信息. 和find相比,whereis查找的速度非 ...
- 测试开发-PC客户端测试要点
一级测试点 二级测试点 安装测试 首次安装(exe和msi格式的不同) 安装程序权限检查 软件安装包的描述和属性信息 静默安装和非静默安装测试 有UAC安装.无UAC安装 联网安装.断网安装 对必 ...
- Linux基础命令---diff
diff 逐行比较两个文本文件,把文件的差异显示到标准输出.如果要指定要比较目录,那么diff命令会比较目录中相同文件名的文件,不会比较子目录. 此命令的适用范围:RedHat.RHEL.Ubuntu ...
- adb shell 命令详解,android, adb logcat
http://www.miui.com/article-275-1.html http://noobjava.iteye.com/blog/1914348 adb shell 命令详解,android ...
- 20145216史婧瑶《网络对抗》逆向及Bof进阶实践
20145216史婧瑶<网络对抗>逆向及Bof进阶实践 基础知识 Shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并将堆栈的返回地址利用缓冲区溢 ...