转载自:http://blog.csdn.net/lalor/article/details/7626678 http://blog.csdn.net/lalor/article/details/7618120
把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数。写一个程序求一棵二叉树中相距最远的两个节点之间的距离。
书上的解法
书中对这个问题的分析是很清楚的,我尝试用自己的方式简短覆述。
计算一个二叉树的最大距离有两个情况:
- 情况A: 路径经过左子树的最深节点,通过根节点,再到右子树的最深节点。
- 情况B: 路径不穿过根节点,而是左子树或右子树的最大距离路径,取其大者。
只需要计算这两个情况的路径距离,并取其大者,就是该二叉树的最大距离。
代码参考编程之美,或者http://www.cnblogs.com/miloyip/archive/2010/02/25/1673114.html
这段代码有几个缺点:
- 算法加入了侵入式(intrusive)的资料nMaxLeft, nMaxRight
- 使用了全局变量 nMaxLen。每次使用要额外初始化。而且就算是不同的独立资料,也不能在多个线程使用这个函数
- 逻辑比较复杂,也有许多 NULL 相关的条件测试。
这个问题的核心是,情况A 及 B 需要不同的信息: A 需要子树的最大深度,B 需要子树的最大距离。只要函数能在一个节点同时计算及传回这两个信息,我是通过一个整形指针保存树中的局部最大距离。然后通过返回值,分别树的最大深度,如果左右子树的最大深度相加大于当前树的最大距离,则更新最大距离,最后返回左右子树中较大的深度,这样可以轻易求得它们父亲的最大深度。(关于建树部分,可以参考http://blog.csdn.net/lalor/article/details/7618120)
代码核心:
int DistanceCore(BinaryTreeNode *root, int *max)
{
//如果节点是叶子节点,则返回0——深度
if (root->m_pLeft == NULL && root->m_pRight == NULL)
{
return 0;
}
//保存左右子树的最大深度
int lDistance = 0;
int rDistance = 0;
//左子树不为空,返回当前节点到左子树的最大深度
if (root->m_pLeft != NULL)
{
lDistance = 1 + DistanceCore(root->m_pLeft, max);
}
if (root->m_pRight != NULL)
{
rDistance = 1 + DistanceCore(root->m_pRight, max);
}
//遍历到当前节点时,能获得的最大距离
if (lDistance + rDistance > *max)
{
//保存当前获得的最大距离
*max = lDistance + rDistance;
}
//返回左右子树中,深度较大的一个
return lDistance > rDistance ? lDistance : rDistance;
}
完整代码如下:
- #include <iostream>
- #include <stdlib.h>
- using namespace std;
- struct BinaryTreeNode
- {
- int m_nValue;
- struct BinaryTreeNode *m_pLeft;
- struct BinaryTreeNode *m_pRight;
- };
- int maxDistance(BinaryTreeNode *root, int *max);
- int DistanceCore(BinaryTreeNode *root,int *max);
- //后序遍历,用于我们建立的二叉树是否正确
- void Traverse( BinaryTreeNode * root);
- BinaryTreeNode* Construct(int *preorder, int *inorder, int lenght);
- BinaryTreeNode* ConstructCore(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder);
- int InsertNodeAtMostRight(BinaryTreeNode * root, BinaryTreeNode * node);
- int main(int argc, char* argv[])
- {
- int preOrder[] = {5, 4, 8, 9, 6, 3, 18, 19, 2};
- int inOrder[] = {9, 8, 6, 3, 4, 5, 19, 18, 2};
- int max;
- //建树
- BinaryTreeNode *parent = Construct(preOrder, inOrder, sizeof(inOrder) / sizeof(inOrder[0]));
- cout << "A树的后序遍历的结果:" << endl;
- Traverse(parent);
- cout << endl;
- BinaryTreeNode *node1 = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
- BinaryTreeNode *node2 = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
- node1->m_nValue = 0;
- node1->m_pLeft = NULL;
- node1->m_pRight = NULL;
- node2->m_nValue = 0;
- node2->m_pLeft = NULL;
- node2->m_pRight = NULL;
- maxDistance(parent, &max);
- cout <<"max distance of tree's nodes : " << max << endl;
- InsertNodeAtMostRight(parent, node1);
- maxDistance(parent, &max);
- cout <<"max distance of tree's nodes after insert node1: " << max << endl;
- InsertNodeAtMostRight(parent, node2);
- maxDistance(parent, &max);
- cout <<"max distance of tree's nodes after insert node2: " << max << endl;
- //测试极端情况,即只有一个节点
- maxDistance(node2, &max);
- cout <<"just one node " << max << endl;
- //测试极端情况,即只有二个节点
- maxDistance(node1, &max);
- cout <<"just two node " << max << endl;
- return 0;
- }
- BinaryTreeNode* Construct(int *preorder, int *inorder, int lenght)
- {
- if (preorder == NULL || inorder == NULL || lenght <= 0)
- {
- return NULL;
- }
- return ConstructCore(preorder, preorder + lenght - 1, inorder, inorder + lenght - 1);
- }
- BinaryTreeNode* ConstructCore(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder)
- {
- int rootValue = startPreorder[0];
- BinaryTreeNode *root = new BinaryTreeNode();
- root->m_nValue = rootValue;
- root->m_pLeft = root->m_pRight = NULL;
- if (startPreorder == endPreorder)
- {//先序遍历已经结束了,那这个时候一定是插入最后一个节点,则应该满足下面的if语句,否则输入的数据有误
- if (startInorder == endInorder && *startPreorder == *startInorder)
- {
- return root;
- }
- else
- {
- cout << "Invalid input" << endl;
- exit(-1);
- }
- }
- int *rootInorder = startInorder;
- while (rootInorder <= endInorder && *rootInorder != rootValue)
- {
- ++rootInorder;
- }
- if (rootInorder <= endInorder && *rootInorder != rootValue)
- {
- cout << "Invalid input" << endl;
- exit(-1);
- }
- int leftLength = rootInorder - startInorder;
- int *leftPreorderEnd = startPreorder + leftLength;
- if (leftLength > 0)
- {
- root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);
- }
- if (leftLength < endPreorder - startPreorder)
- {
- root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder, rootInorder + 1, endInorder);
- }
- return root;
- }
- void Traverse( BinaryTreeNode * root)
- {
- if (root == NULL)
- {
- return;
- }
- else
- {
- Traverse(root->m_pLeft);
- Traverse(root->m_pRight);
- cout << root->m_nValue << " ";
- }
- }
- int maxDistance(BinaryTreeNode *root, int *max)
- {
- //这个函数的主要功能是判断root不为空,且给max赋初值
- if (root == NULL || max == NULL)
- {
- return -1;
- }
- *max = 0;
- return DistanceCore(root, max);
- }
- int DistanceCore(BinaryTreeNode *root, int *max)
- {
- //如果节点是叶子节点,则返回0——深度
- if (root->m_pLeft == NULL && root->m_pRight == NULL)
- {
- return 0;
- }
- //保存左右子树的最大深度
- int lDistance = 0;
- int rDistance = 0;
- //左子树不为空,返回当前节点到左子树的最大深度
- if (root->m_pLeft != NULL)
- {
- lDistance = 1 + DistanceCore(root->m_pLeft, max);
- }
- if (root->m_pRight != NULL)
- {
- rDistance = 1 + DistanceCore(root->m_pRight, max);
- }
- //遍历到当前节点时,能获得的最大距离
- if (lDistance + rDistance > *max)
- {
- //保存当前获得的最大距离
- *max = lDistance + rDistance;
- }
- //返回左右子树中,深度较大的一个
- return lDistance > rDistance ? lDistance : rDistance;
- }
- //为了测试程序写的辅助函数,在树的最最右边插入一个新的节点
- int InsertNodeAtMostRight(BinaryTreeNode * root, BinaryTreeNode * node)
- {
- if (root == NULL || node == NULL)
- {
- return -1;
- }
- while (root->m_pRight != NULL)
- {
- root = root->m_pRight;
- }
- root->m_pRight = node;
- return 0;
- }