二叉树分析(两点最大距离)

转载自:http://blog.csdn.net/lalor/article/details/7626678           http://blog.csdn.net/lalor/article/details/7618120

把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数。写一个程序求一棵二叉树中相距最远的两个节点之间的距离。

书上的解法

书中对这个问题的分析是很清楚的,我尝试用自己的方式简短覆述。

计算一个二叉树的最大距离有两个情况:

  • 情况A: 路径经过左子树的最深节点,通过根节点,再到右子树的最深节点。
  • 情况B: 路径不穿过根节点,而是左子树或右子树的最大距离路径,取其大者。

只需要计算这两个情况的路径距离,并取其大者,就是该二叉树的最大距离。

代码参考编程之美,或者http://www.cnblogs.com/miloyip/archive/2010/02/25/1673114.html

这段代码有几个缺点:

  1. 算法加入了侵入式(intrusive)的资料nMaxLeft, nMaxRight
  2. 使用了全局变量 nMaxLen。每次使用要额外初始化。而且就算是不同的独立资料,也不能在多个线程使用这个函数
  3. 逻辑比较复杂,也有许多 NULL 相关的条件测试。
我的思路:

在看到这题的时候,我没有马上看答案,而是自己思考了一会,得出如下思路,最后跟http://www.cnblogs.com/miloyip/archive/2010/02/25/1673114.html的思路基本一样,只是实现上略有不同。

这个问题的核心是,情况A 及 B 需要不同的信息: A 需要子树的最大深度,B 需要子树的最大距离。只要函数能在一个节点同时计算及传回这两个信息,我是通过一个整形指针保存树中的局部最大距离。然后通过返回值,分别树的最大深度,如果左右子树的最大深度相加大于当前树的最大距离,则更新最大距离,最后返回左右子树中较大的深度,这样可以轻易求得它们父亲的最大深度。(关于建树部分,可以参考http://blog.csdn.net/lalor/article/details/7618120)


代码核心:

int DistanceCore(BinaryTreeNode *root, int *max)
{
//如果节点是叶子节点,则返回0——深度
if (root->m_pLeft == NULL && root->m_pRight == NULL) 
{
return 0;
}

//保存左右子树的最大深度
int lDistance = 0;
int rDistance = 0;

//左子树不为空,返回当前节点到左子树的最大深度
if (root->m_pLeft != NULL) 
{
lDistance = 1 + DistanceCore(root->m_pLeft, max);
}

if (root->m_pRight != NULL) 
{
rDistance = 1 + DistanceCore(root->m_pRight, max);
}

//遍历到当前节点时,能获得的最大距离
if (lDistance + rDistance > *max) 
{
//保存当前获得的最大距离
*max = lDistance + rDistance;
}
//返回左右子树中,深度较大的一个
return lDistance > rDistance ? lDistance : rDistance;
}



完整代码如下:

  1. #include <iostream>  
  2. #include <stdlib.h>  
  3. using namespace std;  
  4.   
  5. struct BinaryTreeNode   
  6. {  
  7.     int m_nValue;  
  8.     struct BinaryTreeNode *m_pLeft;  
  9.     struct BinaryTreeNode *m_pRight;  
  10. };  
  11.   
  12. int maxDistance(BinaryTreeNode *root, int *max);  
  13. int DistanceCore(BinaryTreeNode *root,int *max);  
  14. //后序遍历,用于我们建立的二叉树是否正确  
  15. void Traverse( BinaryTreeNode * root);  
  16. BinaryTreeNode* Construct(int *preorder, int *inorder, int lenght);  
  17. BinaryTreeNode* ConstructCore(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder);  
  18. int InsertNodeAtMostRight(BinaryTreeNode * root, BinaryTreeNode * node);  
  19.   
  20.   
  21. int main(int argc, char* argv[])  
  22. {  
  23.   
  24.     int preOrder[] = {5, 4, 8, 9, 6, 3, 18, 19, 2};  
  25.     int inOrder[] = {9, 8, 6, 3, 4, 5, 19, 18, 2};  
  26.   
  27.     int max;  
  28.   
  29.     //建树  
  30.     BinaryTreeNode *parent = Construct(preOrder, inOrder, sizeof(inOrder) / sizeof(inOrder[0]));  
  31.   
  32.     cout << "A树的后序遍历的结果:" << endl;  
  33.     Traverse(parent);  
  34.     cout << endl;  
  35.   
  36.     BinaryTreeNode *node1 = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));  
  37.     BinaryTreeNode *node2 = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));  
  38.   
  39.     node1->m_nValue = 0;  
  40.     node1->m_pLeft = NULL;  
  41.     node1->m_pRight = NULL;  
  42.   
  43.     node2->m_nValue = 0;  
  44.     node2->m_pLeft = NULL;  
  45.     node2->m_pRight = NULL;  
  46.   
  47.     maxDistance(parent, &max);  
  48.     cout <<"max distance of tree's nodes : " << max << endl;  
  49.   
  50.     InsertNodeAtMostRight(parent, node1);  
  51.     maxDistance(parent, &max);  
  52.     cout <<"max distance of tree's nodes after insert node1: " << max << endl;  
  53.   
  54.     InsertNodeAtMostRight(parent, node2);  
  55.     maxDistance(parent, &max);  
  56.     cout <<"max distance of tree's nodes after insert node2: " << max << endl;  
  57.   
  58.     //测试极端情况,即只有一个节点  
  59.     maxDistance(node2, &max);  
  60.     cout <<"just one node " << max << endl;  
  61.   
  62.     //测试极端情况,即只有二个节点  
  63.     maxDistance(node1, &max);  
  64.     cout <<"just two node " << max << endl;  
  65.     return 0;  
  66. }  
  67.   
  68. BinaryTreeNode* Construct(int *preorder, int *inorder, int lenght)  
  69. {  
  70.     if (preorder == NULL || inorder == NULL || lenght <= 0)   
  71.     {  
  72.         return NULL;  
  73.     }  
  74.     return ConstructCore(preorder, preorder + lenght - 1, inorder, inorder + lenght - 1);  
  75. }  
  76.   
  77. BinaryTreeNode* ConstructCore(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder)  
  78. {  
  79.     int rootValue = startPreorder[0];  
  80.     BinaryTreeNode *root = new BinaryTreeNode();  
  81.     root->m_nValue = rootValue;  
  82.     root->m_pLeft = root->m_pRight = NULL;  
  83.   
  84.     if (startPreorder == endPreorder)   
  85.     {//先序遍历已经结束了,那这个时候一定是插入最后一个节点,则应该满足下面的if语句,否则输入的数据有误  
  86.         if (startInorder == endInorder && *startPreorder == *startInorder)   
  87.         {  
  88.             return root;  
  89.         }  
  90.         else  
  91.         {  
  92.             cout << "Invalid input" << endl;  
  93.             exit(-1);  
  94.         }  
  95.     }  
  96.   
  97.     int *rootInorder = startInorder;  
  98.     while (rootInorder <= endInorder && *rootInorder != rootValue)   
  99.     {  
  100.         ++rootInorder;  
  101.     }  
  102.     if (rootInorder <= endInorder && *rootInorder != rootValue)   
  103.     {  
  104.         cout << "Invalid input" << endl;  
  105.         exit(-1);  
  106.     }  
  107.   
  108.     int leftLength = rootInorder - startInorder;  
  109.     int *leftPreorderEnd = startPreorder + leftLength;  
  110.   
  111.     if (leftLength > 0)   
  112.     {  
  113.         root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);  
  114.     }  
  115.     if (leftLength < endPreorder - startPreorder)   
  116.     {  
  117.         root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder, rootInorder + 1, endInorder);  
  118.     }  
  119.   
  120.     return root;      
  121. }  
  122.   
  123. void Traverse( BinaryTreeNode * root)  
  124. {  
  125.     if (root == NULL)   
  126.     {  
  127.         return;  
  128.     }  
  129.     else  
  130.     {  
  131.         Traverse(root->m_pLeft);  
  132.         Traverse(root->m_pRight);  
  133.         cout << root->m_nValue << "  ";  
  134.     }  
  135. }  
  136. int maxDistance(BinaryTreeNode *root, int *max)  
  137. {  
  138.     //这个函数的主要功能是判断root不为空,且给max赋初值  
  139.     if (root == NULL || max == NULL)   
  140.     {  
  141.         return -1;  
  142.     }  
  143.     *max = 0;  
  144.     return DistanceCore(root, max);  
  145. }  
  146.   
  147. int DistanceCore(BinaryTreeNode *root, int *max)  
  148. {  
  149.     //如果节点是叶子节点,则返回0——深度  
  150.     if (root->m_pLeft == NULL && root->m_pRight == NULL)   
  151.     {  
  152.         return 0;  
  153.     }  
  154.   
  155.     //保存左右子树的最大深度  
  156.     int lDistance = 0;  
  157.     int rDistance = 0;  
  158.   
  159.     //左子树不为空,返回当前节点到左子树的最大深度  
  160.     if (root->m_pLeft != NULL)   
  161.     {  
  162.         lDistance = 1 + DistanceCore(root->m_pLeft, max);  
  163.     }  
  164.   
  165.     if (root->m_pRight != NULL)   
  166.     {  
  167.         rDistance = 1 + DistanceCore(root->m_pRight, max);  
  168.     }  
  169.   
  170.     //遍历到当前节点时,能获得的最大距离  
  171.     if (lDistance + rDistance > *max)   
  172.     {  
  173.         //保存当前获得的最大距离  
  174.         *max = lDistance + rDistance;  
  175.     }  
  176.     //返回左右子树中,深度较大的一个  
  177.     return lDistance > rDistance ? lDistance : rDistance;  
  178. }  
  179.   
  180.   
  181. //为了测试程序写的辅助函数,在树的最最右边插入一个新的节点  
  182. int InsertNodeAtMostRight(BinaryTreeNode * root, BinaryTreeNode * node)  
  183. {  
  184.     if (root == NULL || node == NULL)   
  185.     {  
  186.         return -1;  
  187.     }  
  188.   
  189.     while (root->m_pRight != NULL)   
  190.     {  
  191.         root = root->m_pRight;  
  192.     }  
  193.   
  194.     root->m_pRight = node;  
  195.     return 0;  


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313415.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IT从业的迷思与破解之道(更新)

我只是单纯做技术的程序员&#xff0c;什么靠微信广告攒钱这些&#xff0c;跟我没有半毛钱关系&#xff0c;初衷很简单&#xff0c;只重视正三观的正确技术知识分享在这到处都是线上培训&#xff0c;付费知识的社群里&#xff0c;随便搜个词都有您想要的内容哪轮到我们。技术的…

graphcut 用于最优缝合先寻找_Image Stitching

Graphcut 求解最佳缝合线&#xff1a; 主要参照硕士学位论文《基于不同视点样图的图像修复》 Graphcut 主要参照&#xff1a; http://blog.csdn.net/zouxy09/article/details/8532111 Graph cuts是一种十分有用和流行的能量优化算法&#xff0c;在计算机视觉领域普遍应用于…

.netcore 开发的 iNeuOS 物联网平台部署在 Ubuntu 操作系统,无缝跨平台

1. 概述参见前两篇文章&#xff1a;《iNeuOS完全使用.netcore开发&#xff0c;主要为企业、集成商打造从网关、边缘应用、云端建设的物联网/工业互联网平台产品级解决方案。面向应用场景&#xff1a;&#xff08;1&#xff09;嵌入式硬件网关的开发和部署&#xff0c;形成自己…

按照前序遍历和中序遍历构建二叉树

转载自&#xff1a;http://blog.csdn.net/sbitswc/article/details/26433051 Given preorder and inorder traversal of a tree, construct the binary tree. Note: You may assume that duplicates do not exist in the tree. There is an example._______7______/ …

刷新:重新发现.NET与未来

是新朋友吗&#xff1f;记得先点蓝字关注我哦&#xff5e;微软在比尔盖茨手中创立并崛起, 成为PC互联网时代的霸主&#xff0c;很多70&#xff0c;80后都有MVP Edi Wang 的体验<“ 当时的微软对我来说就是神的存在。因为我认识电脑到使用电脑的一切几乎都离不开这家伟大的公…

合并区间

题目描述 给出一个区间的集合&#xff0c;请合并所有重叠的区间。 示例 1: 输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]] 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].示例 2: 输入: [[1,4],[4,5]] 输出: [[1,5]] 解释: 区间 [1,4] 和 [4,5]…

程序员修神之路--设计一套RPC框架并非易事

菜菜哥&#xff0c;我最近终于把Socket通信调通了这么底层的东西你现在都会了&#xff0c;恭喜你离涨薪又进一步呀http协议不也是利用的Socket吗可以这么说&#xff0c;http协议是基于TCP协议的&#xff0c;底层的数据传输可以说是利用的socket既然Socket通信会了&#xff0c;那…

GPU Shader 编程基础

转载自&#xff1a;http://www.cnblogs.com/youthlion/archive/2012/12/07/2807919.html 几个基本概念&#xff1a; Vertex buffer&#xff1a;存储顶点的数组。当构成模型的所有顶点都放进vertex buffer后&#xff0c;就可以把vertex buffer送进GPU&#xff0c;然后GPU就可…

Azure pipeline 配置根据条件执行脚本

Azure pipeline 配置根据条件执行脚本Intro我的应用通过 azure pipeline 来做持续集成&#xff0c;之前已经介绍了根据不同分支去打包不同的package&#xff0c;具体的就不再这里详细介绍了&#xff0c;可以参考 Solution来看一下修改之后的 azure-pipelines.yaml 示例配置吧&a…

C# 8 新特性 - 可空引用类型

Nullable Reference Type.在写C#代码的时候&#xff0c;你可能经常会遇到这个错误&#xff1a; 但如果想避免NullReferenceException的发生&#xff0c;确实需要做很多麻烦的工作。 可空引用类型 Null Reference Type 所以&#xff0c;C# 8的可空引用类型就出现了。 C# 8可以让…

统计学习笔记(1) 监督学习概论(1)

原作品&#xff1a;The Elements of Statistical Learning Data Mining, Inference, and Prediction, Second Edition, by Trevor Hastie, Robert Tibshirani and Jerome Friedman An Introduction to Statistical Learning. by Gareth JamesDaniela WittenTrevor Hastie andR…

.NET Core 3.0之深入源码理解ObjectPool(一)

写在前面对象池是一种比较常用的提高系统性能的软件设计模式&#xff0c;它维护了一系列相关对象列表的容器对象&#xff0c;这些对象可以随时重复使用&#xff0c;对象池节省了频繁创建对象的开销。它使用取用/归还的操作模式&#xff0c;并重复执行这些操作。如下图所示&…

Deep Boltzmann Machines

转载自&#xff1a;http://blog.csdn.net/win_in_action/article/details/25333671 http://blog.csdn.net/zouxy09/article/details/8775518 深度神经网络&#xff08;Deep neural network&#xff09; 深度学习的概念源于人工神经网络的研究。含多隐层的多层感知器就是一种…

.NET斗鱼直播弹幕客户端(下)

前言在上篇文章中&#xff0c;我们提到了如何使用 .NET连接斗鱼TV直播弹幕的基本操作。然而想要做得好&#xff0c;做得容易扩展&#xff0c;就需要做进一步的代码整理。本文将涉及以下内容&#xff1a;介绍如何使用 ReactiveExtensions&#xff08; Rx&#xff09;&#xff0c…

【 .NET Core 3.0 】框架之十 || AOP 切面思想

本文有配套视频&#xff1a;https://www.bilibili.com/video/av58096866/?p6前言上回《【 .NET Core3.0 】框架之九 || 依赖注入IoC学习 AOP界面编程初探》咱们说到了依赖注入Autofac的使用&#xff0c;不知道大家对IoC的使用是怎样的感觉&#xff0c;我个人表示还是比较可行…

[ASP.NET Core 3框架揭秘] 跨平台开发体验: Docker

对于一个 .NET Core开发人员&#xff0c;你可能没有使用过Docker&#xff0c;但是你不可能没有听说过Docker。Docker是Github上最受欢迎的开源项目之一&#xff0c;它号称要成为所有云应用的基石&#xff0c;并把互联网升级到下一代。Docker是dotCloud公司开源的一款产品&#…

统计学习笔记(4) 线性回归(1)

Basic Introduction In this chapter, we review some of the key ideas underlying the linear regression model, as well as the least squares approach that is most commonly used to fit this model. Basic form: “≈” means “is approximately modeled as”, to …

敏捷这么久,你知道如何开敏捷发布火车吗?

译者&#xff1a;单冰从事项目管理十几年&#xff0c;先后管理传统型项目团队及敏捷创新型团队。负责京东AI事业部敏捷创新、团队工程效率改进及敏捷教练工作。曾经负责手机端京东App项目管理工作5年&#xff0c;带领千人团队实施敏捷转型工作&#xff0c;版本发布从2个月提升为…

Newton Method in Maching Learning

牛顿方法&#xff1a;转自http://blog.csdn.net/andrewseu/article/details/46771947 本讲大纲&#xff1a; 1.牛顿方法(Newton’s method) 2.指数族(Exponential family) 3.广义线性模型(Generalized linear models) 1.牛顿方法 假设有函数&#xff1a;&#xff0c;我们希…

一键分享博客或新闻到Teams好友或频道

在最近的开发者工具更新中&#xff0c;Teams提供了一个Share to Teams的能力&#xff0c;就是在你的网页上面&#xff0c;放置一个按钮&#xff0c;用户点击后&#xff0c;就可以很方便地将当前网页或者你指定的其他网页&#xff0c;分享到Teams好友或频道中。这个开发文档在这…