二叉树中节点的最大的距离
Posted taxue505
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树中节点的最大的距离相关的知识,希望对你有一定的参考价值。
问题定义
把二叉树看成一个图,父子节点之间的连线看成是双向的,定义“距离”为两个节点之间的边数。例如下图中最大距离为红线的条数为6.
分析
方法一、
typedef struct Node
struct Node *pleft; //左孩子
struct Node *pright; //右孩子
char chValue; //该节点的值
int leftMaxValue; //左子树最长距离
int rightMaxValue; //右子树最长距离
LNode, *BinTree;
void findMaxLen(BinTree root, int *maxLen)
//遍历到叶子结点,返回
if(root == NULL)
return;
//如果左子树为空,那么该节点左边最长距离为0
if(root->pleft == NULL)
root->leftMaxValue = 0;
//如果右子树为空,那么该节点右边最长距离为0
if(root->pright == NULL)
root->rightMaxValue = 0;
//如果左子树不为空,递归寻找左子树最长距离
if(root->pleft != NULL)
findMaxLen(root->pleft, maxLen);
//如果右子树不为空,递归寻找右子树最长距离
if(root->pright != NULL)
findMaxLen(root->pright, maxLen);
//计算左子树中距离根节点的最长距离
if(root->pleft != NULL)
if(root->pleft->leftMaxValue > root->pleft->rightMaxValue)
root->leftMaxValue = root->pleft->leftMaxValue + 1;
else
root->leftMaxValue = root->pleft->rightMaxValue + 1;
//计算右子树中距离根节点的最长距离
if(root->pright != NULL)
if(root->pright->leftMaxValue > root->pright->rightMaxValue)
root->rightMaxValue = root->pright->leftMaxValue + 1;
else
root->rightMaxValue = root->pright->rightMaxValue + 1;
//更新最长距离
if(root->leftMaxValue + root->rightMaxValue > *maxLen)
*maxLen = root->leftMaxValue + root->rightMaxValue;
int *maxLen中始终存储的是当前两个节点间的最远距离,在遍历的过程中更新。
下面的程序描述是为了测试上面的代码是否正确,包括建立二叉树,销毁二叉树,打印二叉树:
#include <stdlib.h>
#include <stdio.h>
typedef struct Node
struct Node *pleft; //左孩子
struct Node *pright; //右孩子
char chValue; //该节点的值
int leftMaxValue; //左子树最长距离
int rightMaxValue; //右子树最长距离
LNode, *BinTree;
void findMaxLen(BinTree root, int *maxLen)
//遍历到叶子结点,返回
if(root == NULL)
return;
//如果左子树为空,那么该节点左边最长距离为0
if(root->pleft == NULL)
root->leftMaxValue = 0;
//如果右子树为空,那么该节点右边最长距离为0
if(root->pright == NULL)
root->rightMaxValue = 0;
//如果左子树不为空,递归寻找左子树最长距离
if(root->pleft != NULL)
findMaxLen(root->pleft, maxLen);
//如果右子树不为空,递归寻找右子树最长距离
if(root->pright != NULL)
findMaxLen(root->pright, maxLen);
//计算左子树中距离根节点的最长距离
if(root->pleft != NULL)
if(root->pleft->leftMaxValue > root->pleft->rightMaxValue)
root->leftMaxValue = root->pleft->leftMaxValue + 1;
else
root->leftMaxValue = root->pleft->rightMaxValue + 1;
//计算右子树中距离根节点的最长距离
if(root->pright != NULL)
if(root->pright->leftMaxValue > root->pright->rightMaxValue)
root->rightMaxValue = root->pright->leftMaxValue + 1;
else
root->rightMaxValue = root->pright->rightMaxValue + 1;
//更新最长距离
if(root->leftMaxValue + root->rightMaxValue > *maxLen)
*maxLen = root->leftMaxValue + root->rightMaxValue;
//创建二叉树
void buildBinTree(BinTree *root)
char ch;
scanf("%c", &ch); //输入一个元素
fpurge(stdin);
if(ch == ' ') //若输入的是空格符,表明二叉树为空,置*root为NULL
*root = NULL;
else //若输入的不是空格符,则将该值赋值给根节点的chValue, 递归建立左子树和右子树
*root = (BinTree)malloc(sizeof(LNode));
(*root)->chValue = ch;
(*root)->leftMaxValue = 0;
(*root)->rightMaxValue = 0;
buildBinTree(&(*root)->pleft);
buildBinTree(&(*root)->pright);
//销毁二叉树,释放内存
void destroyBinTree(BinTree *root)
if(*root != NULL)
destroyBinTree(&(*root)->pleft);
destroyBinTree(&(*root)->pright);
free(*root);
*root = NULL;
//前序遍历二叉树
void preOrderTraverse(BinTree root)
if(root != NULL)
preOrderTraverse(root->pleft);
printf("%c", root->chValue);
preOrderTraverse(root->pright);
int main()
BinTree root;
buildBinTree(&root);
preOrderTraverse(root);
printf("\\n");
int maxLen = 0;
findMaxLen(root, &maxLen);
printf("maxLen = %d\\n", maxLen);
destroyBinTree(&root);
这段代码有几个缺点:
- 算法加入了侵入式(intrusive)的资料nMaxLeft, nMaxRight
- 使用了全局变量 nMaxLen。每次使用要额外初始化。而且就算是不同的独立资料,也不能在多个线程使用这个函数
- 逻辑比较复杂,也有许多 NULL 相关的条件测试。
方法二、
定义:过以节点x作为根节点的子树中,节点间的最大距离为Dis(x)。
上图,左图中Dis(根节点)最大,右图中Dis(根节点->left)最大。从上边可以看出每个节点都可能成为最大距离根节点的潜质。
因此可以求出每个Dis(节点),从中得出最大值即为整个二叉树的根节点最大值。
在求过点x的最大距离时,最大距离的两个点有可能出现在三种情况下
- 左子树
- 右子树
- 过节点x
经分析得出以下特点
- 以上三种情况最终必定一叶子结束
- 在第三种情况下必然是左子树高度 与 右子树高度 之和(只有这样,才可能取得最大值)
经过以上分析即可得出递推式
Dis(x) = max(Dis(x->left), Dis(x->right), height(x->left)+height(x->right))
参考代码
int treeDistance(BiTree root)
if(root == NULL)
return 0;
else if(root->left == NULL && root->right == NULL)
return 0;
int dis = max(height(root->left) + height(root->right), treeDistance(root->left), treeDistance(root->right));
if(maxDis < dis)
maxDis = dis;
return dis;
这里用了一个技巧:maxDis是个全局变量,递归一次根节点会遍历到每个节点,在这期间于maxDis比较,从而得出了最大值,而不需要额外的空间。
完整运行代码
#include<iostream>
using namespace std;
typedef struct BiTNode
BiTNode *left;
BiTNode *right;
BiTNode, *BiTree;
int maxDis = 0;
void createTree(BiTree &root)
BiTree left1 = new(BiTNode);
BiTree right1 = new(BiTNode);
left1->left = NULL;
left1->right = NULL;
right1->left = NULL;
right1->right = NULL;
root->left = left1;
root->right = right1;
BiTree left2 = new(BiTNode);
left2->left = NULL;
left2->right = NULL;
BiTree right2 = new(BiTNode);
right2->left = NULL;
right2->right = NULL;
left1->left = left2;
left1->right = right2;
BiTree left3 = new(BiTNode);
left3->left = NULL;
left3->right = NULL;
BiTree right3 = new(BiTNode);
right3->left = NULL;
right3->right = NULL;
left2->left = left3;
left2->right = right3;
void deleteTree(BiTree root)
if(root)
deleteTree(root->left);
deleteTree(root->right);
delete(root);
root = NULL;
int height(BiTree root)
if(root == NULL)
return 0;
else
return height(root->left) > height(root->right) ? height(root->left) + 1 : height(root->right) + 1;
int max(int a, int b, int c)
int tmp = a > b ? a : b;
return tmp > c ? tmp : c;
int treeDistance(BiTree root)
if(root == NULL)
return 0;
else if(root->left == NULL && root->right == NULL)
return 0;
int dis = max(height(root->left) + height(root->right), treeDistance(root->left), treeDistance(root->right));
if(maxDis < dis)
maxDis = dis;
return dis;
int main()
BiTree root = new(BiTNode);
root->right = root->left = NULL;
createTree(root);
cout << "height:" << height(root) << endl;
cout << "treeDistance:" << treeDistance(root) << endl;
cout << "_____________________" << endl;
deleteTree(root);
结果
4
方法三、
我认为这个问题的核心是,情况A 及 B 需要不同的信息: A 需要子树的最大深度,B 需要子树的最大距离。只要函数能在一个节点同时计算及传回这两个信息,代码就可以很简单:
#include <iostream>
using namespace std;
struct NODE
NODE *pLeft;
NODE *pRight;
;
struct RESULT
int nMaxDistance;
int nMaxDepth;
;
RESULT GetMaximumDistance(NODE* root)
if (!root)
RESULT empty = 0, -1 ; // trick: nMaxDepth is -1 and then caller will plus 1 to balance it as zero.
return empty;
RESULT lhs = GetMaximumDistance(root->pLeft);
RESULT rhs = GetMaximumDistance(root->pRight);
RESULT result;
result.nMaxDepth = max(lhs.nMaxDepth + 1, rhs.nMaxDepth + 1);
result.nMaxDistance = max(max(lhs.nMaxDistance, rhs.nMaxDistance), lhs.nMaxDepth + rhs.nMaxDepth + 2);
return result;
计算 result 的代码很清楚;nMaxDepth 就是左子树和右子树的深度加1;nMaxDistance 则取 A 和 B 情况的最大值。
为了减少 NULL 的条件测试,进入函数时,如果节点为 NULL,会传回一个 empty 变量。比较奇怪的是 empty.nMaxDepth = -1,目的是让调用方 +1 后,把当前的不存在的 (NULL) 子树当成最大深度为 0。
除了提高了可读性,这个解法的另一个优点是减少了 O(节点数目) 大小的侵入式资料,而改为使用 O(树的最大深度) 大小的栈空间。这个设计使函数完全没有副作用(side effect)。
以上是关于二叉树中节点的最大的距离的主要内容,如果未能解决你的问题,请参考以下文章