问题描述:
如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数。写一个程序求一棵二叉树中相距最远的两个节点之间的距离。如下图所示,红色的加粗线表示最大距离。
计算一个二叉树的最大距离有两个情况:
情况1: 路径经过左子树的最深节点,通过根节点,再到右子树的最深节点。(左子树深度+右子树深度+2)
情况1: 路径不穿过根节点,而是左子树或右子树的最大距离路径,取其大者。(左子树或右子树最大距离MaxLen)
只需要计算这两个情况的路径距离,并取其大者,就是该二叉树的最大距离。下面是两种情况的示意图:
实现代码如下:
/*解法:求二叉树中节点最大距离
情况一:穿越左子树最深节点、根节点到右子树最深节点
情况二:就是左子树(或右子树)节点最大距离
*/
int max(int a,int b)
{
return a>b?a:b;
}
struct Result{
int MaxDepth;//最大深度
int MaxDis;//最远两节点距离
};
class BinaryTree{//二叉树的递归定义
private:
int data;
BinaryTree *pLChild;//左子树根节点
BinaryTree *pRChild;//右子树根节点
public:
BinaryTree();
BinaryTree(int data);
~BinaryTree();
BinaryTree* createNode(int data);
void buildTree(BinaryTree *pLChild , BinaryTree *pRChild);
void destoryTree();//删除以某节点为根的下面所有子树
void preOrder();//先序遍历
void inOrder();//中序遍历
void postOrder();//后序遍历
Result findMaxDis();//寻找以this为根的两节点最大距离
};
BinaryTree* BinaryTree::createNode(int data)//创建新节点,分配存储空间,返回指向该节点的指针
{
BinaryTree *treeNode = new BinaryTree;
treeNode->data = data;
return treeNode;
}
BinaryTree::BinaryTree()//对树初始化
{
pLChild = pRChild = NULL;
data = INT_MIN;
}
BinaryTree::BinaryTree(int data)
{
pLChild = pRChild = NULL;
this->data = data;
}
BinaryTree::~BinaryTree()
{
}
void BinaryTree::buildTree(BinaryTree *pLChild , BinaryTree *pRChild)
{
if(!this)
return;
this->pLChild = pLChild;
this->pRChild = pRChild;
}
void BinaryTree::preOrder()
{
if(!this)
return;
else{
cout<<this->data<<" ";
this->pLChild->preOrder();
this->pRChild->preOrder();
}
}
void BinaryTree::inOrder()
{
if(!this)
return;
else{
this->pLChild->inOrder();
cout<<this->data<<" ";
this->pRChild->inOrder();
}
}
void BinaryTree::postOrder()
{
if(!this)
return;
else{
this->pLChild->postOrder();
this->pRChild->postOrder();
cout<<this->data<<" ";
}
}
void BinaryTree::destoryTree()//删除以某节点为根的下面所有子树
{
if(!this)
return;
if(this->pLChild){//左子树不为空
this->pLChild->destoryTree();//递归删除左子树
delete this->pLChild;//删掉以pLChild为根的下面子树后,置pLChild的父节点相应孩子域为NULL
this->pLChild = NULL;
}
if(this->pRChild){//右子树不为空
this->pRChild->destoryTree();//递归删除右子树
delete this->pRChild;
this->pRChild = NULL;
}
}
Result BinaryTree::findMaxDis()
{
Result emptyRes = {-1,0};//开始条件,考虑到叶子节点处左右孩子有两个Null,此时为了分别加1深度为0所以设为-1
if(!this)
return emptyRes;
Result res;//以this节点为根的子树MaxDepth和MaxDis
Result resL = this->pLChild->findMaxDis();//this左子树MaxDepth和MaxDis
Result resR = this->pRChild->findMaxDis();//this右子树MaxDepth和MaxDis
res.MaxDepth = max(resL.MaxDepth , resR.MaxDepth) + 1;//左右子树最大深度+1
res.MaxDis = max(max(resL.MaxDis , resR.MaxDis) , resL.MaxDepth+resR.MaxDepth+2);//左右子树最大距离以及左右子树深度和取最大值
return res;
}
int main()
{
BinaryTree*n1 = new BinaryTree(1);
BinaryTree*n2 = new BinaryTree(2);
BinaryTree*n3 = new BinaryTree(3);
BinaryTree*n4 = new BinaryTree(4);
BinaryTree*n5 = new BinaryTree(5);
BinaryTree*n6 = new BinaryTree(6);
n1->buildTree(n2,n3);
n2->buildTree(n4,NULL);
n3->buildTree(NULL,n5);
n4->buildTree(NULL,NULL);
n5->buildTree(n6,NULL);
n6->buildTree(NULL,NULL);
//n3->destoryTree();
Result res = n1->findMaxDis();
cout<<res.MaxDepth<<" "<<res.MaxDis<<endl;
return 0;
}
对于递归问题:
1.先弄清楚递归的顺序,往往假设后续的调用已完成,然后继续前面的逻辑;
2.理清递归的逻辑,递归用来干什么(本例中是计算两边最长距离);
3.递归退出的边界条件,哪些地方要return;
下面是书上的方法:
struct BinaryTree{//二叉树的递归定义
BinaryTree(int d):data(d),pLChild(NULL),pRChild(NULL){}
int data;
BinaryTree *pLChild;//左子树根节点
BinaryTree *pRChild;//右子树根节点
int MaxLDis;//左子树最大距离
int MaxRDis;//右子树最大距离
};
//计算以pRoot为根节点的子树最大节点距离
int nMaxLen = 0;//全局变量保存当前树最长节点距离
void findMaxDis(BinaryTree *pRoot)
{
if(pRoot == NULL)//空节点
return ;
//---递归截止条件,两种可返回条件:左节点为空或右节点为空
if(!pRoot->pLChild)//如果左孩子为空
pRoot->MaxLDis = 0;
if(!pRoot->pRChild)//如果右孩子为空
pRoot->MaxRDis = 0;
//---递归寻找左右子树最大节点距离
if(pRoot->pLChild)//如果左子树存在
findMaxDis(pRoot->pLChild);
if(pRoot->pRChild)//如果右子树存在
findMaxDis(pRoot->pRChild);
if(pRoot->pLChild){
int tempMax = 0;
if(pRoot->pLChild->MaxLDis > pRoot->pLChild->MaxRDis){//更新左子树MaxLDis
tempMax = pRoot->pLChild->MaxLDis;
}else{tempMax = pRoot->pLChild->MaxRDis;}
pRoot->MaxLDis = tempMax+1;
}
if(pRoot->pRChild){
int tempMax = 0;
if(pRoot->pRChild->MaxLDis > pRoot->pRChild->MaxRDis){//更新左子树MaxLDis
tempMax = pRoot->pRChild->MaxLDis;
}else{tempMax = pRoot->pRChild->MaxRDis;}
pRoot->MaxRDis = tempMax+1;
}
//---算出了this的左子树和右子树的MaxDis,接下来更新this自身的MaxDis
if(pRoot->MaxLDis+pRoot->MaxRDis > nMaxLen)
nMaxLen = pRoot->MaxLDis+pRoot->MaxRDis;
}
int main()
{
BinaryTree *n1 = new BinaryTree(1);
BinaryTree *n2 = new BinaryTree(2);
BinaryTree *n3 = new BinaryTree(3);
BinaryTree *n4 = new BinaryTree(4);
BinaryTree *n5 = new BinaryTree(5);
BinaryTree *n6 = new BinaryTree(6);
n1->pLChild = n2;
n2->pLChild = n4;
n1->pRChild = n3;
n3->pRChild = n5;
n2->pRChild = n6;
findMaxDis(n1);
cout<<nMaxLen<<endl;
return 0;
}