您的位置:首页 > 其它

变形二叉树中节点的最大距离(树的最长路径)——非递归解法

2016-04-13 15:52 399 查看

问题描写叙述:

假设我们把二叉树看成一个图,父子节点之间的连线看成是双向的。我们姑且定义"距离"为两节点之间边的个数。

写一个程序,求一棵二叉树中相距最远的两个节点之间的距离。測试用的树:

n1

/ \

n2 n3

/ \

n4 n5

/ \ / \

n6 n7 n8 n9

/ /

n10 n11

不幸的是。我一開始就把题目看错了:把“父子节点之间的连线看成是双向的”理解成为,在节点的定义中真的有指向父节点的指针。。。。

将错就错。我干脆把错误理解的题目先做出来再说。于是。为了实现非递归解法。自己定义了一种奇怪的数节点struct。。





于是。事情变成了:我为了解决题目。改了题目要求。。。。

。。





事实上对于原题。依据树结构,用我所定义的节点,初始化一棵变形二叉树,再用这样的非递归解法求解就可以。仅仅只是初始化树还须要做些工作。

这样的解法也不是全然没有意义。



。。

对于原题的解法。以后再说。

算法:

题目就是求一棵树中的最长路径

对于节点t,以它为根的树的最长路径longstpath一定是下列三个数中的最大值

①t的左子树的longstpath

②t的右子树的longstpath

③t的左子树的深度+t的右子树的深度+2

——结论1

所以对于每一个节点。有两个重要的属性:①以该节点为根的树的深度②以该节点为根的树的最大路径长度

从每一个叶节点開始,自底向上进行处理。

每次处理的过称为:

若该节点两个属性均已确定,将它们“告知”父节点。父节点得到全部子节点的属性后,依据结论1方可确定自己的两个属性。继续向上“报告”自己的属性。

对于没有了解到全部子节点属性的父节点,让他在每一次处理中”等待“子节点的报告,显然。须要一个队列queue存储正在等待的节点。

代码实现:

#include<iostream>
#include "Queue.h"
using namespace std;

//节点结构体
struct BinaryTreeNode
{
BinaryTreeNode* father = NULL;//指向父节点
BinaryTreeNode* left = NULL;
BinaryTreeNode* right = NULL;
int arrived = 0;//记录子树深度值到达的数目。取值为0或1或2
int depth = 0;//以此节点为根的树的深度
int longstpath = 0;//以此节点为根的树中的最长路径
bool stored = false;//是否已入列等待
};

//取大值
int max2(int a, int b)
{
if (a > b)
return a;
else return b;
}

//取大值
int max3(int a, int b, int c)
{
return max2(max2(a, b), c);
}

//依据不同情况(有的节点无左/右子节点),更新longstpath
//longstpath一定是下面三数中的最大值:左子树的longstpath。右子树的longstpath。左右子树深度和+2
void SetLongstpath(BinaryTreeNode* temp)
{
int lpath, rpath, ldepth, rdepth;
if (temp->left)
{
lpath = temp->left->longstpath;   ldepth = temp->left->depth;
}
else lpath = ldepth = 0;
if (temp->right)
{
rpath = temp->right->longstpath;   rdepth = temp->right->depth;
}
else rpath = rdepth = 0;
temp->longstpath = max3(lpath, rpath, ldepth + rdepth + 2);//更新最长路径longstpath
}

int FindPath(Queue<BinaryTreeNode*> &queue)
{
BinaryTreeNode* temp;
while (!queue.IsEmpty())
{
queue.Delete(temp);
temp->stored = false;
if (temp->arrived == 2)//子节点都到达了,万事俱备
{
SetLongstpath(temp);//更新temp的Longstpath
if (temp->father)//若不是根节点。,则上移该节点(即对父节点进行处理)
{
temp->father->depth = max2(temp->father->depth, temp->depth + 1);//更新父节点的深度值
temp->father->arrived++;//到达子节点数目+1
if (!temp->father->stored)//说明这是第一个到达的子节点。该父节点从未入列,则将其入列
{
queue.Add(temp->father);
temp->father->stored = true;
}
}
else//根节点,返回longstpath
return temp->longstpath;
}
if (temp->arrived == 1)//有子节点还没到,更新longstpath的条件不充分。又一次入列等待子节点
{
queue.Add(temp);
temp->stored = true;
}
}
}

void main()
{
BinaryTreeNode* n1 = new BinaryTreeNode;
BinaryTreeNode* n2 = new BinaryTreeNode;
BinaryTreeNode* n3 = new BinaryTreeNode;
BinaryTreeNode* n4 = new BinaryTreeNode;
BinaryTreeNode* n5 = new BinaryTreeNode;
BinaryTreeNode* n6 = new BinaryTreeNode;
BinaryTreeNode* n7 = new BinaryTreeNode;
BinaryTreeNode* n8 = new BinaryTreeNode;
BinaryTreeNode* n9 = new BinaryTreeNode;
BinaryTreeNode* n10 = new BinaryTreeNode;
BinaryTreeNode* n11 = new BinaryTreeNode;
//构造二叉树
n2->father = n3->father = n1;
n4->father = n5->father = n2;
n6->father = n7->father = n4;
n8->father = n9->father = n5;
n10->father = n6;
n11->father = n9;
n6->left = n10;
n4->left = n6; n4->right = n7;
n9->left = n11;
n5->left = n8; n5->right = n9;
n2->left = n4; n2->right = n5;
n1->left = n2; n1->right = n3;

n3->arrived = 2;//叶节点初始为2
n7->arrived = 2;
n8->arrived = 2;
n10->arrived = 2;
n11->arrived = 2;
n6->arrived = 1;//但孩子节点初始为1
n9->arrived = 1;

Queue<BinaryTreeNode*> queue;
queue.Add(n3);
n3->stored = true;
queue.Add(n7);
n7->stored = true;
queue.Add(n8);
n8->stored = true;
queue.Add(n10);
n10->stored = true;
queue.Add(n11);
n11->stored = true;

cout << "最大路径长度:" << FindPath(queue) << endl;
system("pause");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: