【id:76】【20分】B. DS二叉树—二叉树结点的最大距离

题目描述

      二叉树两个结点的距离是一个结点经过双亲结点,祖先结点等中间结点到达另一个结点经过的分支数。二叉树结点的最大距离是所有结点间距离的最大值。例如,下图所示二叉树结点最大距离是3,C和D的距离。

          二叉树用先序遍历顺序创建,#表示空树。计算二叉树结点最大距离和最大距离的两个结点(假设二叉树中取最大距离的两个结点唯一)。

输入

测试次数T

第2行之后的T行,每行为一棵二叉树先序遍历结果(#表示空树)

输出

 对每棵二叉树,输出树的结点最大距离和最大距离的结点,输出格式见样例。

输入样例1 

4
A##
ABC##EF#G###D##
ABEH###F#K###
AB###

输出样例1

0:
5:G D
4:H K
1:B A

以下是思路

  以图一二叉树为例,该树节点的最大距离的路径应该为:G-F-E-B-A-D。而且可知这两节点肯定是叶子节点。如果节点数小于等于2倒比较简单,max为0不存在;为1一个为叶子节点另一个为根节点;为2则先输出左子树节点再输出右子树节点(根据先序遍历的顺序)。但如果有3个以上的叶子节点就比较麻烦;如果是从叶子节点开始往回找公共父亲节点的话又不方便实现。想到这里就应该要想到多半要用递归来做这题了。

  首先来看两种情况,图一的最长路径经过根节点,而图二的最长路径不经过根节点。

  那到底该咋做捏?首先我们可以先序遍历这颗二叉树,在遍历的过程中对每一个节点计算其左子树和右子树深度之和(均取最大值),并记录最深的左右子树节点。简单来说,在先序遍历时,把每一个节点都当作一个新的根节点,然后去计算其左右子树最深的位置之和。

  以图一为例,假设现在在A节点。对其左右左右子树遍历可知最深的地方是G和D节点。而对于图二来说A右子树为空,那么就以先序遍历的顺序看看B节点的左右子树,发现最深的位置是H和K节点。

  

 

   那么首先是建树,这题一没给权值二不用父亲节点,那包含基本的成员就行。但由于对于每个节点都要计算左右深度,并且过程分为先序遍历->查找左右子树深度,那么应该添加对应的成员和函数。所以代码如下

class Node
{
public:
	Node* left, * right;
	char data;
	int left_len = 0;
	int right_len = 0;
	Node() { left = right = NULL;data = '-'; }
};

class Tree
{
private:
	string str;
	int pos;
public:
	Node* root;
	int max = 0;
	Tree(string s) { str = s;pos = 0;root = create(); }
	Node* create();
	int depthoftree(Node* end, int& maxdepth, int curdepth, Node* tmp);
	void pre(Node* end, int& max, Node* A, Node* B);
};

    首先是查找深度,以该节点为根节点,对其左右子树不断查找,寻找最深的位置。那么应当用递归实现先序遍历,得到当前节点左右子树的深度,并与这棵树当前的最大深度进行比较。那么代码如下

int Tree::depthoftree(Node* end, int& maxdepth, int curdepth, Node* tmp)
{
	if (end == NULL)
	{
		return -1;
	}
	depthoftree(end->left, maxdepth, curdepth + 1, tmp);
	depthoftree(end->right, maxdepth, curdepth + 1, tmp);
	if (curdepth > maxdepth)
	{
		maxdepth = curdepth;
		tmp->data = end->data;
	}
	return maxdepth;
}

  最后是先序遍历,保存每次最深的两个节点和最大深度,并先序遍历该树直至遍历完成。‘

void Tree::pre(Node* end, int& max, Node* A, Node* B)
{
	if (end)
	{
		int d1 = -1, d2 = -1;
		Node* tmp1 = new Node();
		Node* tmp2 = new Node();
		int curmax = depthoftree(end->left, d1, 0, tmp1) + depthoftree(end->right, d2, 0, tmp2) +2;
		if (curmax > max)
		{
			A->data = tmp1->data;
			B->data = tmp2->data;
			max = curmax;
		}
		pre(end->left, max, A, B);
		pre(end->right, max, A, B);
	}
}

 

以下是代码

 

#include <iostream>
using namespace std;

class Node
{
public:
	Node* left, * right;
	char data;
	int left_len = 0;
	int right_len = 0;
	Node() { left = right = NULL;data = '-'; }
};

class Tree
{
private:
	string str;
	int pos;
public:
	Node* root;
	int max = 0;
	Tree(string s) { str = s;pos = 0;root = create(); }
	Node* create();
	int depthoftree(Node* end, int& maxdepth, int curdepth, Node* tmp);
	void pre(Node* end, int& max, Node* A, Node* B);
};
Node* Tree::create()
{
	char tmp = str[pos];
	pos++;
	if (tmp == '#')
	{
		return NULL;
	}
	else
	{
		Node* node = new Node();
		node->data = tmp;
		node->left = create();
		node->right = create();
		return node;
	}
}
int Tree::depthoftree(Node* end, int& maxdepth, int curdepth, Node* tmp)
{
	if (end == NULL)
	{
		return -1;
	}
	depthoftree(end->left, maxdepth, curdepth + 1, tmp);
	depthoftree(end->right, maxdepth, curdepth + 1, tmp);
	if (curdepth > maxdepth)
	{
		maxdepth = curdepth;
		tmp->data = end->data;
	}
	return maxdepth;
}
void Tree::pre(Node* end, int& max, Node* A, Node* B)
{
	if (end)
	{
		int d1 = -1, d2 = -1;
		Node* tmp1 = new Node();
		Node* tmp2 = new Node();
		int curmax = depthoftree(end->left, d1, 0, tmp1) + depthoftree(end->right, d2, 0, tmp2) +2;
		if (curmax > max)
		{
			A->data = tmp1->data;
			B->data = tmp2->data;
			max = curmax;
		}
		pre(end->left, max, A, B);
		pre(end->right, max, A, B);
	}
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		string str;
		cin >> str;
		Tree tree(str);
		int max = 0;
		Node* A = new Node();
		Node* B = new Node();
		tree.pre(tree.root, max, A, B);
		cout << max << ":";
		if (max == 1)
		{
			cout << A->data << " " << tree.root->data;
		}
		else if (max > 1)
		{
			cout << A->data << " " << B->data;
		}
		cout << endl;
	}
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值