[编程之美] PSet3.8 求二叉树中节点的最大距离

问题描述:

       如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数。写一个程序求一棵二叉树中相距最远的两个节点之间的距离。如下图所示,红色的加粗线表示最大距离。

                     

计算一个二叉树的最大距离有两个情况:
      情况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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值