到现在为止,看过的书+代码有一定量了,并且也参加了个比赛,给自己的总体感觉:编程需要的是灵活的头脑,书里的东西只是讲个规则、思想,其实际实现可以千差万别!   潜在的规则+灵活的思维 = 程序!

在做面试题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的更多相关文章

  1. 剑指Offer:面试题15——链表中倒数第k个结点(java实现)

    问题描述 输入一个链表,输出该链表中倒数第k个结点.(尾结点是倒数第一个) 结点定义如下: public class ListNode { int val; ListNode next = null; ...

  2. 剑指offer面试题3 二维数组中的查找(c)

    剑指offer面试题三:

  3. 剑指Offer——笔试题+知识点总结

    剑指Offer--笔试题+知识点总结 情景回顾 时间:2016.9.23 12:00-14:00 19:00-21:00 地点:山东省网络环境智能计算技术重点实验室 事件:笔试 注意事项:要有大局观, ...

  4. C++版 - 剑指offer之面试题37:两个链表的第一个公共结点[LeetCode 160] 解题报告

    剑指offer之面试题37 两个链表的第一个公共结点 提交网址: http://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?t ...

  5. C++版 - 剑指offer 面试题23:从上往下打印二叉树(二叉树的层次遍历BFS) 题解

    剑指offer  面试题23:从上往下打印二叉树 参与人数:4853  时间限制:1秒  空间限制:32768K 提交网址: http://www.nowcoder.com/practice/7fe2 ...

  6. C++版 - 剑指offer 面试题39:判断平衡二叉树(LeetCode 110. Balanced Binary Tree) 题解

    剑指offer 面试题39:判断平衡二叉树 提交网址:  http://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId= ...

  7. Leetcode - 剑指offer 面试题29:数组中出现次数超过一半的数字及其变形(腾讯2015秋招 编程题4)

    剑指offer 面试题29:数组中出现次数超过一半的数字 提交网址: http://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163 ...

  8. C++版 - 剑指Offer 面试题39:二叉树的深度(高度)(二叉树深度优先遍历dfs的应用) 题解

    剑指Offer 面试题39:二叉树的深度(高度) 题目:输入一棵二叉树的根结点,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度.例如:输入二叉树 ...

  9. C++版 - 剑指offer 面试题24:二叉搜索树BST的后序遍历序列(的判断) 题解

    剑指offer 面试题24:二叉搜索树的后序遍历序列(的判断) 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true.否则返回false.假设输入的数组的任意两个 ...

  10. C++版 - 剑指Offer 面试题45:圆圈中最后剩下的数字(约瑟夫环问题,ZOJ 1088:System Overload类似)题解

    剑指Offer 面试题45:圆圈中最后剩下的数字(约瑟夫环问题) 原书题目:0, 1, - , n-1 这n个数字排成一个圈圈,从数字0开始每次从圆圏里删除第m个数字.求出这个圈圈里剩下的最后一个数字 ...

随机推荐

  1. HTML+CSS学习笔记(9)- CSS的继承、层叠和特殊性

    标签:HTML+CSS 继承 CSS的某些样式是具有继承性的,那么什么是继承呢?继承是一种规则,它允许样式不仅应用于某个特定html标签元素,而且应用于其后代.比如下面代码:如某种颜色应用于p标签,这 ...

  2. 用实体框架搭建MVC程序框架(全部)

    第一步:1.新建项目 2.新建domain类库 3.新建Data类库 4.为上面的1.2.3添加实体框架nuget包.(可以右键管理nuget包来查找entityframework,当然也可以通过程序 ...

  3. UI4_UITableViewSectionIndex

    // AppDelegate.m // UI4_UITableViewSectionIndex // // Created by zhangxueming on 15/7/14. // Copyrig ...

  4. 8.samba server与client配置

    server端 1.安装samba:yum install -y samba\* 增加samba用户: useradd smb用户名               smbpasswd -a smb用户名 ...

  5. WP开发笔记——页面传参

    WP APP页面与页面之间参数的传递可以通过程序的App类设置全局变量. 由于App 类继承自Application类,而通过Application的Current属性可以获取到与当前程序关联的App ...

  6. 方便实用的jQuery checkbox复选框全选功能

    // 主复选框 <input type="checkbox" id="ck" name="ckAll">// 子复选框项 < ...

  7. winform 批量导入本地sql文件,批量导入mdb(access)文件到sqlserver

    0.数据库连接 private void button1_Click(object sender, EventArgs e) { this.btnUpdate.Enabled = false; #re ...

  8. 使用tortoise git管理gitolite版本库

    gitolite-admin是用于管理git版本库的版本库,将其从服务器上clone下来. 使用tortoise git clone的时候需要指定私钥,私钥的格式是ppk的,需要使用putty的PUT ...

  9. linux前景到底怎么样啊?

    我就不长篇大论,举四个例子你看看. 1.目下最热最潮最流行的云计算技术的背后是虚拟化和网格技术,而虚拟化和网格技术基本是Linux的天下,目前虚拟化的三大家:Vmware,Xen,Hyper-V中,市 ...

  10. Python脚本控制的WebDriver 常用操作 <十九> 获取测试对象的状态

    下面将使用webdriver来模拟测试中观察测试对象的状态的操作 测试用例场景 在web自动化测试中,我们需要获取测试对象的四种状态 是否显示.使用element.is_displayed()方法: ...