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

转载自: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;在计算机视觉领域普遍应用于…

最后一个单词的长度

题目描述 给定一个仅包含大小写字母和空格 ’ ’ 的字符串&#xff0c;返回其最后一个单词的长度。 如果不存在最后一个单词&#xff0c;请返回 0 。 说明&#xff1a;一个单词是指由字母组成&#xff0c;但不包含任何空格的字符串。 示例: 输入: "Hello World"…

.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______/ …

线程间通讯方式

线程间通讯方式 1&#xff1a;同步&#xff08;synchronized&#xff09; 2&#xff1a;共享变量&#xff08;volatile&#xff09; 2&#xff1a;wait/notify()机制 3&#xff1a;管道通信就是使用java.io.PipedInputStream 和 java.io.PipedOutputStream进行通信 进程间…

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

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

OpenCV Stitching_detailed 详解

算法流程函数&#xff1a; 1. (*finder)(img, features[i]) Mathematical explanation: Refer to BRIEF: Binary Robust Independent Elementary Features and ORB: An efficient alternative to SIFT or SURF ...\sources\modules\stitching\src\matchers.cpp void OrbFe…

合并区间

题目描述 给出一个区间的集合&#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…

监督学习和非监督学习

转自&#xff1a;http://blog.csdn.net/warrior_zhang/article/details/41453327 机器学习的常用方法&#xff0c;主要分为有监督学习(supervised learning)和无监督学习(unsupervised learning)。 监督学习&#xff0c;就是人们常说的分类&#xff0c;通过已有的训练样本&am…

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

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

Spring boot starter

1&#xff1a;Spring boot starter及项目中的类似运用 1&#xff1a;Spring boot starter的两种方式 引入pom文件&#xff0c;自动管理jar版本根据spring.factories配置文件&#xff0c;加载config的各种bean spring boot约定大于配置理念在这里有体现。 2&#xff1a;项目…

统计学习笔记(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;并重复执行这些操作。如下图所示&…

查看日志文件的方法

对于一般大小的日志文件&#xff0c;直接使用tail命令即可。 对于大日志文件&#xff0c;并且还在不停刷新的&#xff0c;使用more或less命令 对于很大的log文件用more不能直接跳到文件末尾向前查看。 这时可以用less来查看文件时&#xff0c;在command模式下按G跳到文件末尾&…

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; 深度学习的概念源于人工神经网络的研究。含多隐层的多层感知器就是一种…

生产问题

1&#xff1a;MQ过快 有个业务场景是&#xff1a;先创建一条记录&#xff08;1&#xff09;&#xff0c;然后发mq&#xff0c;最后更新这条记录的状态&#xff08;2&#xff09;。 收到mq之后&#xff0c;再更新状态&#xff08;3&#xff09;。 问题出在mq快于本地事务&…