题目:给定一棵二叉树和其中的一个节点,如何找出中序遍历序列的下一个节点?树中的节点除了有两个分别指向左、右子节点的指针,还有一个指向父节点的指针。

测试用例:

  • 普通二叉树(完全二叉树,不完全二叉树)。
  • 特殊二叉树(所有节点都没有右子节点的二叉树;所有节点都没有左子节点的二叉树;只有一个节点的二叉树;二叉树的根节点指针为nullptr)。
  • 不同位置的节点的下一个节点(下一个节点为当前节点的右子节点、右子树的最左子节点、父节点、跨层的父节点等;当前节点没有下一个节点)。

测试代码:

void Test(char* testName, BinaryTreeNode* pNode, BinaryTreeNode* expected)
{
if(testName != nullptr)
printf("%s begins: ", testName);
BinaryTreeNode* pNext = GetNext(pNode);
if(pNext == expected)
printf("Passed.\n");
else
printf("FAILED.\n");
} // 8
// 6 10
// 5 7 9 11
void Test1_7()
{
BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6);
BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10);
BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5);
BinaryTreeNode* pNode7 = CreateBinaryTreeNode(7);
BinaryTreeNode* pNode9 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNode11 = CreateBinaryTreeNode(11); ConnectTreeNodes(pNode8, pNode6, pNode10);
ConnectTreeNodes(pNode6, pNode5, pNode7);
ConnectTreeNodes(pNode10, pNode9, pNode11); Test("Test1", pNode8, pNode9);
Test("Test2", pNode6, pNode7);
Test("Test3", pNode10, pNode11);
Test("Test4", pNode5, pNode6);
Test("Test5", pNode7, pNode8);
Test("Test6", pNode9, pNode10);
Test("Test7", pNode11, nullptr); DestroyTree(pNode8);
} // 5
// 4
// 3
// 2
void Test8_11()
{
BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5);
BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
BinaryTreeNode* pNode3 = CreateBinaryTreeNode(3);
BinaryTreeNode* pNode2 = CreateBinaryTreeNode(2); ConnectTreeNodes(pNode5, pNode4, nullptr);
ConnectTreeNodes(pNode4, pNode3, nullptr);
ConnectTreeNodes(pNode3, pNode2, nullptr); Test("Test8", pNode5, nullptr);
Test("Test9", pNode4, pNode5);
Test("Test10", pNode3, pNode4);
Test("Test11", pNode2, pNode3); DestroyTree(pNode5);
} // 2
// 3
// 4
// 5
void Test12_15()
{
BinaryTreeNode* pNode2 = CreateBinaryTreeNode(2);
BinaryTreeNode* pNode3 = CreateBinaryTreeNode(3);
BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);
BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5); ConnectTreeNodes(pNode2, nullptr, pNode3);
ConnectTreeNodes(pNode3, nullptr, pNode4);
ConnectTreeNodes(pNode4, nullptr, pNode5); Test("Test12", pNode5, nullptr);
Test("Test13", pNode4, pNode5);
Test("Test14", pNode3, pNode4);
Test("Test15", pNode2, pNode3); DestroyTree(pNode2);
} void Test16()
{
BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5); Test("Test16", pNode5, nullptr); DestroyTree(pNode5);
}

本题考点:

  • 考查应聘者对二叉树中序遍历的理解程度。只有对二叉树的遍历算法有了深刻的理解,应聘者才有可能准确找出每个节点的中序遍历的下一个节点。
  • 考查应聘者分析复杂问题的能力。应聘者只有画出二叉树的结构图、通过具体的例子找出中序遍历下一个节点的规律,才有可能设计出可行的算法。

实现代码:

#include <cstdio>

struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
BinaryTreeNode* m_pParent;
}; BinaryTreeNode* GetNext(BinaryTreeNode* pNode)
{
if(pNode == nullptr)
return nullptr;
BinaryTreeNode* pNext = nullptr;
if(pNode->m_pRight != nullptr)
{
BinaryTreeNode* pRight = pNode->m_pRight;
while(pRight->m_pLeft != nullptr)
pRight = pRight->m_pLeft;
pNext = pRight;
}
else if(pNode->m_pParent != nullptr)
{
BinaryTreeNode* pCurrent = pNode;
BinaryTreeNode* pParent = pNode->m_pParent;
while(pParent != nullptr && pCurrent == pParent->m_pRight)
{
pCurrent = pParent;
pParent = pParent->m_pParent;
}
pNext = pParent;
}
return pNext;
}
// ==================== 辅助代码用来构建二叉树 ====================
BinaryTreeNode* CreateBinaryTreeNode(int value)
{
BinaryTreeNode* pNode = new BinaryTreeNode();
pNode->m_nValue = value;
pNode->m_pLeft = nullptr;
pNode->m_pRight = nullptr;
pNode->m_pParent = nullptr;
return pNode;
} void ConnectTreeNodes(BinaryTreeNode* pParent, BinaryTreeNode* pLeft, BinaryTreeNode* pRight)
{
if(pParent != nullptr)
{
pParent->m_pLeft = pLeft;
pParent->m_pRight = pRight;
if(pLeft != nullptr)
pLeft->m_pParent = pParent;
if(pRight != nullptr)
pRight->m_pParent = pParent;
}
} void PrintTreeNode(BinaryTreeNode* pNode)
{
if(pNode != nullptr)
{
printf("value of this node is: %d\n", pNode->m_nValue); if(pNode->m_pLeft != nullptr)
printf("value of its left child is: %d.\n", pNode->m_pLeft->m_nValue);
else
printf("left child is null.\n"); if(pNode->m_pRight != nullptr)
printf("value of its right child is: %d.\n", pNode->m_pRight->m_nValue);
else
printf("right child is null.\n");
}
else
{
printf("this node is null.\n");
}
printf("\n");
} void PrintTree(BinaryTreeNode* pRoot)
{
PrintTreeNode(pRoot); if(pRoot != nullptr)
{
if(pRoot->m_pLeft != nullptr)
PrintTree(pRoot->m_pLeft);
if(pRoot->m_pRight != nullptr)
PrintTree(pRoot->m_pRight);
}
} void DestroyTree(BinaryTreeNode* pRoot)
{
if(pRoot != nullptr)
{
BinaryTreeNode* pLeft = pRoot->m_pLeft;
BinaryTreeNode* pRight = pRoot->m_pRight;
delete pRoot;
pRoot = nullptr;
DestroyTree(pLeft);
DestroyTree(pRight);
}
}
int main(int argc, char* argv[])
{
Test1_7();
Test8_11();
Test12_15();
Test16();
}

剑指offer笔记面试题8----二叉树的下一个节点的更多相关文章

  1. 【剑指offer】面试题 8. 二叉树的下一个结点

    面试题 8. 二叉树的下一个结点 NowCoder 题目描述 给定一棵二叉树和其中的一个结点,如何找出中序遍历顺序的下一个结点?树中的结点除了有两个分别指向左右子结点的指针以外,还有一个指向父结点的指 ...

  2. 剑指Offer(书):二叉树的下一个节点

    题目:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 分析:若一个节点有右子树,那么他的下一个节点就是他右子树中 ...

  3. 《剑指offer》面试题39 二叉树的深度(java)

    摘要: 今天翻到了<剑指offer>面试题39,题目二中的解法二是在函数的参数列表中通过指针的方式进行传值,而java是没有指针的,所以函数要进行改造.然而我翻了下别人的java版本(我就 ...

  4. 剑指offer笔记面试题7----重建二叉树

    题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如,输入前序遍历序列{1, 2, 4, 7, 3, 5, 6, 8}和中序遍历序列 ...

  5. 【剑指offer】面试题 55. 二叉树的深度

    面试题 55. 二叉树的深度 题目一:二叉树的深度 题目描述:输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. Java 实现 ...

  6. 【剑指offer】面试题 23. 链表中环的入口节点

    面试题 23. 链表中环的入口节点

  7. 《剑指Offer》面试题-重建二叉树

    题目描述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7 ...

  8. 《剑指offer》面试题25 二叉树中和为某一值的路径 Java版

    (判断是否有从根到叶子节点的路径,其和为给定值.记录这些路径.) 我的方法:这道题我是按照回溯的思路去做的,我们需要一个数据结构来保存和删除当前递归函数中添加的值.这里要打印一条路径,我们可以选择Li ...

  9. 《剑指offer》面试题19 二叉树的镜像 Java版

    书中方法:这道题目可能拿到手没有思路,我们可以在纸上画出简单的二叉树来找到规律.最后我们发现,镜像的实质是对于二叉树的所有节点,交换其左右子节点.搞清楚获得镜像的方法,这道题实际上就变成了一道二叉树遍 ...

随机推荐

  1. Android 自定义饼状图

    github 地址:https://github.com/dkest/PieView 简单分析 其实根据我们上面的知识已经能自己制作一个饼状图了.不过制作东西最重要的不是制作结果,而是制作思路. 相信 ...

  2. Java修炼——异常的概念以及处理方式(捕获异常)

    异常概念分类 异常( Exception 也称例外)就是在程序的运行过程中 所发生的不正常的事件,它会中断正在运行的程序  所需文件找不到  网络连接不通或中断  算术运算错 (被零除-)  ...

  3. Koa - 初体验(写个接口)

    前言 不会node.js的前端不是一个好前端! 这几年node.js确实是越来越火了,好多公司对node.js都开始有要求.虽说前端不一定要会后端,但想要成为一个优秀的前端,node.js是必经之路. ...

  4. C和C++从零开始系列(一)

    今天开始写下一系列C和C++从入门开始的文章. 简单说几句C和C++的关系.C语言早于C++. C语言 贝尔实验室的Ken Thompson发明了 UNIX,当时有个B语言的.后来D.M.Ritchi ...

  5. 【Java Web开发学习】远程方法调用RMI

    Java RMI 远程方法调用Remote Method Invocation 转载:http://www.cnblogs.com/yangchongxing/p/9078061.html 1.创建远 ...

  6. Web基础了解版02-JavaScript

    JavaScript 特性 ① 解释型语言.JavaScript是一种解释型的脚本语言,JavaScript是在程序的运行过程中逐行进行解释,不需要被编译为机器码再执行. ② 面向对象.JavaScr ...

  7. JAVA可视化闹钟源码

    概述 一些同学的Java课设有这样一个问题,比较感兴趣就做了一下 功能介绍: 1.可增加闹钟 2.可删除闹钟 3.时间到了响铃 4.关闭闹钟不会丢失闹钟(因为闹钟存储在txt文件中,不会因程序关闭就终 ...

  8. 注解slf4j的日志该用哪个级别

    slf4j的日志级别分为五种 info.debug.error.warn.trane 常用的是这是三个.         info  一般处理业务逻辑的时候使用,就跟 system.err打印一样,用 ...

  9. centos7 启动停止命令

    apache启动systemctl start httpd停止systemctl stop httpd重启systemctl restart httpd mysql启动systemctl start ...

  10. gitbook 入门教程之网站域名备案 icp 插件

    欢迎访问 gitbook-plugin-icp 官网