变形二叉树中节点的最大距离(树的最长路径)——非递归解法
问题描写叙述:
假设我们把二叉树看成一个图,父子节点之间的连线看成是双向的。我们姑且定义"距离"为两节点之间边的个数。
写一个程序,求一棵二叉树中相距最远的两个节点之间的距离。測试用的树:
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"); }