求二叉树中两个节点最远的距离

一说到二叉树,就有很多题目,今天在编程之美中看到了二叉树中两个节点最远的距离。所以给想借机写一篇博客。

在开始之前,我们先想想,两个最常节点的最远距离是怎么样的?

情况一:最大距离可能一个在左子树,一个在右子树中,通过根节点;


情况二:也可能出现在左/右子树中,不经过根节点。

求二叉树中两个节点最远的距离_第1张图片

大体就是这样,我们要如何来解决呢?


给大家看看《编程之美》中它是如何决解的:

<span style="font-size:24px;">// 数据结构定义
struct NODE
{
    NODE* pLeft;        // 左子树
    NODE* pRight;       // 右子树
    int nMaxLeft;       // 左子树中的最长距离
    int nMaxRight;      // 右子树中的最长距离
    char chValue;       // 该节点的值
};
 
int nMaxLen = 0;
 
// 寻找树中最长的两段距离
void FindMaxLen(NODE* pRoot)
{
    // 遍历到叶子节点,返回
    if(pRoot == NULL)
    {
        return;
    }
 
    // 如果左子树为空,那么该节点的左边最长距离为0
    if(pRoot -> pLeft == NULL)
    {
        pRoot -> nMaxLeft = 0; 
    }
 
    // 如果右子树为空,那么该节点的右边最长距离为0
    if(pRoot -> pRight == NULL)
    {
        pRoot -> nMaxRight = 0;
    }
 
    // 如果左子树不为空,递归寻找左子树最长距离
    if(pRoot -> pLeft != NULL)
    {
        FindMaxLen(pRoot -> pLeft);
    }
 
    // 如果右子树不为空,递归寻找右子树最长距离
    if(pRoot -> pRight != NULL)
    {
        FindMaxLen(pRoot -> pRight);
    }
 
    // 计算左子树最长节点距离
    if(pRoot -> pLeft != NULL)
    {
        int nTempMax = 0;
        if(pRoot -> pLeft -> nMaxLeft > pRoot -> pLeft -> nMaxRight)
        {
            nTempMax = pRoot -> pLeft -> nMaxLeft;
        }
        else
        {
            nTempMax = pRoot -> pLeft -> nMaxRight;
        }
        pRoot -> nMaxLeft = nTempMax + 1;
    }
 
    // 计算右子树最长节点距离
    if(pRoot -> pRight != NULL)
    {
        int nTempMax = 0;
        if(pRoot -> pRight -> nMaxLeft > pRoot -> pRight -> nMaxRight)
        {
            nTempMax = pRoot -> pRight -> nMaxLeft;
        }
        else
        {
            nTempMax = pRoot -> pRight -> nMaxRight;
        }
        pRoot -> nMaxRight = nTempMax + 1;
    }
 
    // 更新最长距离
    if(pRoot -> nMaxLeft + pRoot -> nMaxRight > nMaxLen)
    {
        nMaxLen = pRoot -> nMaxLeft + pRoot -> nMaxRight;
    }
}</span>

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

而,我想了想,写出了这样的代码:

<span style="font-size:24px;">void _FindMaxDis(BSTreeNode *pNode, int &deepth, int &maxdis)    //这里的两个数,我都用的是引用,读者知道为什么? 
{  
    if (pNode==NULL)  
    {  
        deepth=0;maxdis=0;  
        return;  
    } </span>
<span style="font-size:24px;">    int l_deepth=0,r_deepth=0;  
    int l_maxdis=0,r_maxdis=0;  
  
    if (pNode->m_pleft)  
        FindMaxDis(pNode->m_pleft,l_deepth,l_maxdis);  
    if (pNode->m_pright)  
        FindMaxDis(pNode->m_pright,r_deepth,r_maxdis);  
  
    deepth = (l_deepth > r_deepth ? l_deepth : r_deepth) + 1;  
  
    maxdis = l_maxdis > r_maxdis ? l_maxdis : r_maxdis ;  
  
    maxdis = (l_deepth+r_deepth) > maxdis ? (l_deepth+r_deepth) : maxdis;  
  
}</span>
<span style="font-size:24px;">  
int FindMaxDis(BSTreeNode *pNode)  
{  
    int deepth, maxdis;  
    _FindMaxDis(pNode,deepth,maxdis);  
  
    return maxdis;  
}  </span>
其实做做这个题,大体思路都是一致的。但是,我们要考虑很多。在这个方面,推荐读者去看看《代码大全》

我来说一说这个代码的好处吧。

提高了可读性,另一个优点是减少了 O(节点数目) 大小的侵入式资料,而改为使用 O(树的最大深度) 大小的栈空间。


本博文只是对二叉树中两个节点最远的距离的解法,做了粗略的概述,如有更好的解法或者不同的看法,请留言。

你可能感兴趣的:(二叉树中两个节点最远的距离)