今天中午的时候有人问了我一个问题:求二叉树中节点的最大距离。这是《编程之美》上的一个问题。
花了一中午的时间总算解决了这个问题,有一点是很明确的:如果把树看做是一个图的话,它必然是连通的,任一节点总有路径到其他任何节点,这个题目就是求这样最长的一条路径。距离最大的两个节点可能是一个在左子树,一个在右子树,也可能是在一个子树上。下面的图展示了这两种情况
我试着把这个问题转化一下:树中的每一个节点都是一颗子树的根,对于这棵子树而言,它左子树的高度是Lm,右子树的高度是Rm,求所有子树中(Lm + Rm)的最大值是多少?(虽然不知道这样的问题在实际生产中是否有意义,也许有吧),还是用图比较直观。
在图上标出了每个节点左子树的长度和右子树的长度,叶子节点的左右子树长度都是0。每个节点左子树的长度是左孩子的左子树长度和左孩子右子树长度中较长的那个再加1,,这句话比较绕,但是好理解,比如A->Lm = Max(B->Lm,B->Rm) + 1,这样很明了了吧。有了上面的信息之后,我们可以计算每棵子树的(Lm + Rm),其中最大者就是结果。由于树的定义是递归的,所以用递归的方式更容易编程。
算法步骤:
(1)初始化二叉树,并将每个节点Lm和Rm初始化为0,定义二叉树中节点的最大距离Max = -1
(2)为了计算一个节点的Lm和Rm,需要采用后序遍历策略,递归的计算出它左孩子Left的Lm,Rm,Lm = max(Left->Lm + Left->Rm) + 1;和右孩子Right的Lm,Rm,Rm = max(Right->Lm,Right->Rm) + 1;
(3)对于每一个节点,计算Lm + Rm,如果其值大于Max,则Max = Lm + Rm,最后Max就是最大距离。
树节点的声明如下:
typedef struct TreeNode *Position;
typedef Position Tree;
struct TreeNode {
int element;
Position left;
Position right;
int lm;
int rm;
};
static int max = -1;//保存最远的距离
实际算法如下:
/*计算一棵树中,距离最远两个节点之间的距离*/
/*具体算法:每个节点有两个域分别用来保存它左子树的最大高度lm和右子树的最大高度rm
*将lm + rm与当前已知最远的距离相比较,如果大于max,则更新Max的值
*/
int maxDist(Tree root) {
//如果树是空的,则返回0
if(root == NULL)
return 0;
if(root->left != NULL) {
root->lm = maxDist(root->left) + 1;
}
if(root->right != NULL)
root->rm = maxDist(root->right) + 1;
//如果以该节点为根的子树中有最大的距离,那就更新最大距离
int sum = root->rm + root->lm;
if(sum > max) {
max = sum;
}
return root->rm > root->lm ? root->rm : root->lm;
}
上面的代码对每个节点只处理一次,所以时间复杂度是O(N),N是节点个数。
转载请注明:喻红叶《求二叉树中节点的最大距离》