求二叉树的宽度(结点的最大距离)

问题定义

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

书上的解法

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

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

  • 情况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;  
  196. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值