一说到二叉树,就有很多题目,今天在编程之美中看到了二叉树中两个节点最远的距离。所以给想借机写一篇博客。
在开始之前,我们先想想,两个最常节点的最远距离是怎么样的?
情况一:最大距离可能一个在左子树,一个在右子树中,通过根节点;
情况二:也可能出现在左/右子树中,不经过根节点。
大体就是这样,我们要如何来解决呢?
给大家看看《编程之美》中它是如何决解的:
<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(树的最大深度) 大小的栈空间。
本博文只是对二叉树中两个节点最远的距离的解法,做了粗略的概述,如有更好的解法或者不同的看法,请留言。