问题定义
如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数。写一个程序求一棵二叉树中相距最远的两个节点之间的距离。
对于任意一个节点,以该节点为根,假设这个根有k个孩子节点,那么距离最远的两个节点U与V之间的路径与这个根节点的关系有两种。
1).若路径经过Root,则U和V属于不同子树的,且它们都是该子树中到根节点最远的节点,否则跟它们的距离最远相矛盾
2).如果路径不经过Root,那么它们一定属于根的k个子树之一,并且它们也是该子树中相距最远的两个顶点
因此,问题就可以转化为在字数上的解,从而能够利用动态规划来解决。
设第K棵子树中相距最远的两个节点:Uk和Vk,其距离定义为d(Uk,Vk),那么节点Uk或Vk即为子树K到根节点Rk距离最长的节点。不失一般性,我们设Uk为子树K中道根节点Rk距离最长的节点,其到根节点的距离定义为d(Uk,R)。取d(Ui,R)(1<=i<=k)中最大的两个值max1和max2,那么经过根节点R的最长路径为max1+max2+2,所以树R中相距最远的两个点的距离为:max{d(U1,V1),…, d(Uk,Vk),max1+max2+2}。
- 情况A: 路径经过左子树的最深节点,通过根节点,再到右子树的最深节点。
- 情况B: 路径不穿过根节点,而是左子树或右子树的最大距离路径,取其大者。
只需要计算这两个情况的路径距离,并取其大者,就是该二叉树的最大距离。
1 // 数据结构定义 2 struct NODE 3 { 4 NODE* pLeft; // 左子树 5 NODE* pRight; // 右子树 6 int nMaxLeft; // 左子树中的最长距离 7 int nMaxRight; // 右子树中的最长距离 8 char chValue; // 该节点的值 9 };10 int nMaxLen = 0;11 // 寻找树中最长的两段距离 12 void FindMaxLen(NODE* pRoot)13 {14 // 遍历到叶子节点,返回 15 if(pRoot == NULL)16 {17 return;18 }19 // 如果左子树为空,那么该节点的左边最长距离为0 20 if(pRoot -> pLeft == NULL)21 {22 pRoot -> nMaxLeft = 0;23 }24 // 如果右子树为空,那么该节点的右边最长距离为0 25 if(pRoot -> pRight == NULL)26 {27 pRoot -> nMaxRight = 0;28 }29 // 如果左子树不为空,递归寻找左子树最长距离 30 if(pRoot -> pLeft != NULL)31 {32 FindMaxLen(pRoot -> pLeft);33 }34 // 如果右子树不为空,递归寻找右子树最长距离 35 if(pRoot -> pRight != NULL)36 {37 FindMaxLen(pRoot -> pRight);38 }39 // 计算左子树最长节点距离 40 if(pRoot -> pLeft != NULL)41 {42 int nTempMax = 0;43 if(pRoot -> pLeft -> nMaxLeft > pRoot -> pLeft -> nMaxRight)44 {45 nTempMax = pRoot -> pLeft -> nMaxLeft;46 }47 else48 {49 nTempMax = pRoot -> pLeft -> nMaxRight;50 }51 pRoot -> nMaxLeft = nTempMax + 1;52 }53 // 计算右子树最长节点距离 54 if(pRoot -> pRight != NULL)55 {56 int nTempMax = 0;57 if(pRoot -> pRight -> nMaxLeft > pRoot -> pRight -> nMaxRight)58 {59 nTempMax = pRoot -> pRight -> nMaxLeft;60 }61 else62 {63 nTempMax = pRoot -> pRight -> nMaxRight;64 }65 pRoot -> nMaxRight = nTempMax + 1;66 }67 // 更新最长距离 68 if(pRoot -> nMaxLeft + pRoot -> nMaxRight > nMaxLen)69 {70 nMaxLen = pRoot -> nMaxLeft + pRoot -> nMaxRight;71 }72 }