剑指offer--面试题5
到现在为止,看过的书+代码有一定量了,并且也参加了个比赛,给自己的总体感觉:编程需要的是灵活的头脑,书里的东西只是讲个规则、思想,其实际实现可以千差万别! 潜在的规则+灵活的思维 = 程序!
在做面试题5时,发现Utilities文件夹下的内容太好了,基本上是那些数据结构的实现:链表、二叉树、树等(缺个图),准备通过学习这些代码来深入理解各个数据结构及其接口/成员函数。
拿该题来说,解决单链表!!!
题目:逆序打印单链表
一、自己写单链表类及其操作
花了一下午时间,无语了。。。
1、List.h
//单链表数据结构及基本操作 //最大节点数
const int MAXLENGTH = ;
//节点
struct ListNode
{
int m_Value;
ListNode* m_pNext;
}; //List类
class List
{
private:
ListNode LNode;
int MaxLength;
public:
//constructor and deconstructor
List();
virtual ~List();
//单链表操作
//1. 创建节点
ListNode* CreateListNode(int value);
//2. 创建链表或者将节点加到链尾
void CreateFrontOrAddToTail(ListNode** pHead, int value);
//3. 在第i个节点之前插入新的节点
void ListInsert(ListNode* pHead, int i, int value);
//4. 删除value=e的节点
void RemoveListNode(ListNode** pHead,int value);
//5. 查找第一个value=e的节点
int FindListNode(ListNode* pHead,int value);
//6. 销毁链表
void DestoryList(ListNode* pHead);
//7. 链表元素个数
int ListLength(ListNode* pHead);
};
2、List.cpp
//List.cpp #include "List.h"
#include <iostream> List::List()
{
LNode.m_Value = ;
LNode.m_pNext = NULL;
MaxLength = MAXLENGTH;
} List::~List()
{ } //1. 创建节点
ListNode* List::CreateListNode(int value)
{
ListNode* pNew = new ListNode;
pNew->m_Value = value;
pNew->m_pNext = NULL;
}
//2. 创建链表或者将节点加到链尾
void List::CreateFrontOrAddToTail(ListNode** pHead, int value)
{
if(pHead == NULL)
return;
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;
} }
//3. 在第i个节点之前插入新的节点
void List::ListInsert(ListNode* pHead, int i, int value)
{
if(pHead == NULL || i >= MaxLength)
return;
ListNode* pNew = CreateListNode(value);
ListNode* pNode = *pHead;
ListNode* preNode = *pHead;
i--;
while(i && pNode->m_pNext != NULL)
{
preNode = pNode;
pNode = pNode->m_pNext;
i--;
}
if(i == )
{
preNode->m_pNext = pNew;
pNew->m_pNext = pNode;
}
else
cout<<"Failed!"<<endl;
}
//4. 删除value=e的第一个节点
bool List::RemoveListNode(ListNode** pHead,int value)
{
if(pHead == NULL || *pHead == NULL)
return false;
ListNode* pToBeDeleted = NULL;
if((*pHead)->m_Value == value)
{
pToBeDeleted = *pHead;
*pHead = (*pHead)->m_pNext;
}
else
{
ListNode* pNode = *pHead;
while(pNode->m_pNext != NULL && pNode->m_pNext->m_Value != value)
pNode = pNode->m_pNext;
if(pNode->m_pNext != NULL && pNode->m_pNext->m_Value == value)
{
pToBeDeleted = pNode->m_pNext;
pNode->m_pNext = pNode->m_pNext->m_pNext;
}
}
if(pToBeDeleted != NULL)
{
delete pToBeDeleted;
pToBeDeleted = NULL;
return true;
}
return false;
} //5. 查找第一个value=e的节点,返回其位置
int List::FindListNode(ListNode* pHead,int value)
{
int i = ;
ListNode* pNode = pHead;
while(pNode != NULL && pNode->m_Value != value)
{
i++;
pNode = pNode->m_pNext;
}
if(pNode != NULL && pNode->m_Value == value)
return i;
else
return ; }
//6. 销毁链表
void List::DestoryList(ListNode* pHead)
{
ListNode* pNode = pHead;
while(pHead != NULL)
{
pNode = pHead;
pHead = pHead->m_pNext;
delete pNode;
}
}
//7. 链表元素个数
int List::ListLength(ListNode* pHead)
{
ListNode* pNode = pHead;
int i = ;
while(pNode != NULL)
{
i++;
pNode = pNode->m_pNext;
}
return i;
}
未测试过。。。因为想继续做面试题5了,进度太慢了!!!
二、面试题5整理:
逆序打印单链表,首先想到的便是通过扫描链表,并同时用栈存储每个值,最后利用栈的LIFO特点打印即可。但是,鉴于自己的水平,并没有用过C++中stl里的stack,因此想了另一种方法,即将扫描链表时所得到的值存入到一个数组中,最后逆序打印即可。这种方法固然可行,但效率上必然低于栈的。所以综合以上分析,又学习了stl中的stack,具体见上一篇博客。最后,怎么也没想到可以用递归的方式求解。。。
根据作者代码思想,做了如下改动:
void PrintListReversingly_Iteratively(ListNode* pHead)
{
std::stack<int> nodes; ListNode* pNode = pHead;
while(pNode != NULL)
{
nodes.push(pNode->m_nValue);
pNode = pNode->m_pNext;
} int value;
while(!nodes.empty())
{
value = nodes.top();
printf("%d\t", value);
nodes.pop();
}
}
这里将stack的元素设置为了m_nValue的类型,仔细想想后,认为还是原代码更合理,原因如下:
原代码中,节点地址入栈,因此栈中每个元素所占存储是固定的,在32位操作系统下,指针(地址)占4字节;但如果存储的是节点数据元素,那么每个元素所占存储很可能大于4字节;
void PrintListReversingly_Recursively(ListNode* pHead)
{
if(pHead == NULL)
{
return;
}
else
{
PrintListReversingly_Recursively(pHead->m_pNext);
printf("%d\t", pHead->m_nValue);
}
}
剑指offer--面试题5的更多相关文章
- 剑指Offer:面试题15——链表中倒数第k个结点(java实现)
问题描述 输入一个链表,输出该链表中倒数第k个结点.(尾结点是倒数第一个) 结点定义如下: public class ListNode { int val; ListNode next = null; ...
- 剑指offer面试题3 二维数组中的查找(c)
剑指offer面试题三:
- 剑指Offer——笔试题+知识点总结
剑指Offer--笔试题+知识点总结 情景回顾 时间:2016.9.23 12:00-14:00 19:00-21:00 地点:山东省网络环境智能计算技术重点实验室 事件:笔试 注意事项:要有大局观, ...
- C++版 - 剑指offer之面试题37:两个链表的第一个公共结点[LeetCode 160] 解题报告
剑指offer之面试题37 两个链表的第一个公共结点 提交网址: http://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?t ...
- C++版 - 剑指offer 面试题23:从上往下打印二叉树(二叉树的层次遍历BFS) 题解
剑指offer 面试题23:从上往下打印二叉树 参与人数:4853 时间限制:1秒 空间限制:32768K 提交网址: http://www.nowcoder.com/practice/7fe2 ...
- C++版 - 剑指offer 面试题39:判断平衡二叉树(LeetCode 110. Balanced Binary Tree) 题解
剑指offer 面试题39:判断平衡二叉树 提交网址: http://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId= ...
- Leetcode - 剑指offer 面试题29:数组中出现次数超过一半的数字及其变形(腾讯2015秋招 编程题4)
剑指offer 面试题29:数组中出现次数超过一半的数字 提交网址: http://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163 ...
- C++版 - 剑指Offer 面试题39:二叉树的深度(高度)(二叉树深度优先遍历dfs的应用) 题解
剑指Offer 面试题39:二叉树的深度(高度) 题目:输入一棵二叉树的根结点,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度.例如:输入二叉树 ...
- C++版 - 剑指offer 面试题24:二叉搜索树BST的后序遍历序列(的判断) 题解
剑指offer 面试题24:二叉搜索树的后序遍历序列(的判断) 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true.否则返回false.假设输入的数组的任意两个 ...
- C++版 - 剑指Offer 面试题45:圆圈中最后剩下的数字(约瑟夫环问题,ZOJ 1088:System Overload类似)题解
剑指Offer 面试题45:圆圈中最后剩下的数字(约瑟夫环问题) 原书题目:0, 1, - , n-1 这n个数字排成一个圈圈,从数字0开始每次从圆圏里删除第m个数字.求出这个圈圈里剩下的最后一个数字 ...
随机推荐
- hdu 1716(dfs)
题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=1716 排列2 Problem Description Ray又对数字的列产生了兴趣:现 ...
- C语言清除输入缓存方法记录[转]
原文:http://www.tomytime.com/archives/218/ fflush()函数是标准的作法. setbuf(stdin,NULL)是GCC下可用的一种方法. scanf(&qu ...
- (转)RabbitMQ消息队列(五):Routing 消息路由
上篇文章中,我们构建了一个简单的日志系统.接下来,我们将丰富它:能够使用不同的severity来监听不同等级的log.比如我们希望只有error的log才保存到磁盘上. 1. Bindings绑定 上 ...
- ionic2 Navigation实现报错:No component factory found for "MyComponent"
ionic2 写的代码里面,跳转的时候报了一个 No component factory found for "RechargeSucceed" recharge() { let ...
- [Silverlight] Visual Studio2010不能安装Silverlight4_Tools,提示语言不一致
今天在装Silverlight4_Tools时出现“必须先安装与 Silverlight Tools 4 语言版本相一致的 Visual Studio 2010.Visual Web Develope ...
- MFC控件随窗口大小变化原理及实现
本文主要针对MFC的dialog,实现控件随窗口大小变化. 原理:首先获取dialog的初始大小,当窗口发送变动时,调用OnSize事件和方法,计算缩放比例,然后对界面中的所有控件进行缩放和布局. 实 ...
- 使用inotify检测linux目录内文件变化
#include <unistd.h> #include <sys/inotify.h> #include <stdio.h> #include <error ...
- 怎样按字母顺序(ABCDEF)动态添加控件
考试系统中题库设计时,我想动态添加选项,顺序按ABCDEF这样,点击一下按钮添加A(radiobutton),再点击添加B,如此依次添加.本人比较菜,求达人写一个方法. private void bu ...
- jquery 在页面中三种写法
jQuery 分 2 个系列版本 1.x 与 2.x,主要的区别在于 2.x 不再兼容 IE6.7.8浏览器,这样做的目的是为了兼容移动端开发.由于减少了一些代码,使得该版本比 jQuery 1.x ...
- Mongodb Java Driver 参数配置解析
要正确使用Mongodb Java Driver,MongoClientOptions参数配置对数据库访问的并发性能影响极大. connectionsPerHost:与目标数据库能够建立的最大conn ...