二叉树中节点的最大的距离
来源:互联网 发布:局域网ip mac扫描导出 编辑:程序博客网 时间:2024/05/21 17:28
问题定义
把二叉树看成一个图,父子节点之间的连线看成是双向的,定义“距离”为两个节点之间的边数。例如下图中最大距离为红线的条数为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)。
- 二叉树中节点的最大距离
- 二叉树中节点的最大距离
- 二叉树中节点的最大距离
- 二叉树中节点的最大距离
- 二叉树中节点的最大距离
- 二叉树中节点的最大距离
- 二叉树中节点的最大距离
- 二叉树中节点的最大距离
- 二叉树中节点的最大距离
- 二叉树中节点的最大距离
- 【二叉树】求二叉树中节点的最大距离
- 二叉树中节点的最大的距离
- 3.8求二叉树中节点的最大距离
- 求二叉树中节点的最大距离
- 求二叉树中节点的最大距离
- 求二叉树中节点的最大距离
- 求二叉树中节点的最大距离
- 求二叉树中节点的最大距离
- 二叉树的下一个结点
- 腾讯新产品砸了所有鉴黄师的饭碗
- nyoj 37 51nod oj 1092 回文字符串 【LCS变形】
- 2016更新:极客学院视频全套下载
- Spinner下拉菜单简单使用
- 二叉树中节点的最大的距离
- 数据库操作
- Android混淆编译、反混淆、反编译
- uva11270Tiling Dominoes
- HDU 3652 裸数位DP
- 论表单设计规范
- Advanced Fruits
- JAVA学习代码——数组排序
- 实数