我们怎样才能找到二叉树的中心? 什么是最有效的算法。虽然二叉树的中心将是与树的直径相对应的路径的中点。我们可以在不知道路径的情况下找到树的直径,是否有找到二叉树中心的类似技术?
答案 0 :(得分:4)
如果你知道直径:D
你知道树的最大深度:M
那么你的中心将位于最深路径上的(M-(D / 2))节点(来自根)(根据奇偶校验可能是M - (D-1)/ 2),你需要检查自己)
如果从M到节点的根到叶的路径超过1条,那么中心就是根。 (仅当最长路径通过根时才为真)
修改强>
回答你的评论。
如果没有通过root。让我们在直径上采用D / 2节点,它仍将位于直径路径的最长边(在所有情况下,从根到叶的最长路径)。因此,M-D / 2仍然从根本上代表这一点。
从根部取M-D / 2次与从最长路径的叶子说D / 2次相同。
我清楚了吗?您可能只想绘制它来检查它。
答案 1 :(得分:1)
如果您使用递归方法(通过使用树的高度来计算直径),则可以通过存储已遍历的节点列表以线性时间O(N)计算此值(see this website here )。
例如,在我上面发布的链接上调整线性时间diameter
函数,这样您也可以收集已访问过的节点列表,而不仅仅是距离信息。在每次递归调用时,您将选择与较长遍历距离一起使用的列表。表示树直径的列表中间将是树的“中心”。
您的设置如下所示:
typedef struct linked_list
{
tree_node* node;
linked_list* next;
} linked_list;
typedef struct list_pair
{
linked_list* tree_height;
linked_list* full_path;
} list_pair;
//some standard functions for working with the structure data-types
//they're not defined here for the sake of brevity
void back_insert_node(linked_list** tree, tree_node* add_node);
void front_insert_node(linked_list** tree, tree_node* add_node);
int list_length(linked_list* list);
void destroy_list(linked_list* list);
linked_list* copy_list(linked_list* list);
linked_list* append_list(linked_list* first, linked_list* second);
//main function for finding the diameter of the tree
list_pair diameter_path(tree_node* tree)
{
if (tree == NULL)
{
list_pair return_list_pair = {NULL, NULL};
return return_list_pair;
}
list_pair rhs = diameter_path(tree->right);
list_pair lhs = diameter_path(tree->left);
linked_list* highest_tree =
list_length(rhs.tree_height) > list_length(lhs.tree_height) ?
rhs.tree_height : lhs.tree_height;
linked_list* longest_path =
list_length(rhs.full_path) > list_length(lhs.full_path) ?
rhs.full_path : lhs.full_path;
//insert the current node onto the sub-branch with the highest height
//we need to make sure that the full-path, when appending the
//rhs and lhs trees, will read from left-to-right
if (highest_tree == rhs.tree_height)
front_insert_node(highest_tree, tree);
else
back_insert_node(highest_tree, tree);
//make temporary copies of the subtrees lists and append them to
//create a full path that represents a potential diameter of the tree
linked_list* temp_rhs = copy_list(rhs.tree_height);
linked_list* temp_lhs = copy_list(lhs.tree_height);
linked_list* appended_list = append_list(temp_lhs, temp_rhs);
longest_path =
list_length(appended_list) > list_length(longest_path) ?
appended_list : longest_path;
list_pair return_list_pair;
return_list_pair.tree_height = copy_list(highest_tree);
return_list_pair.full_path = copy_list(longest_path);
destroy_list(rhs.tree_height);
destroy_list(rhs.full_path);
destroy_list(lhs.tree_height);
destroy_list(lhs.full_path);
return return_list_pair;
}
现在该函数返回full_path
结构成员中的一系列指针,这些指针可用于循环并找到将成为树的“中心”的中间节点。
P.S。我知道利用复制功能并不是最快的方法,但我想要更清楚,而不是制作速度更快但指针太多的东西。
答案 2 :(得分:0)
Optimized implementation: The above implementation can be optimized by calculating the
height in the same recursion rather than calling a height() separately.
/*The second parameter is to store the height of tree.
Initially, we need to pass a pointer to a location with value
as 0. So, function should be used as follows:
int height = 0;
struct node *root = SomeFunctionToMakeTree();
int diameter = diameterOpt(root, &height); */
int diameterOpt(struct node *root, int* height)
{
/* lh --> Height of left subtree
rh --> Height of right subtree */
int lh = 0, rh = 0;
/* ldiameter --> diameter of left subtree
rdiameter --> Diameter of right subtree */
int ldiameter = 0, rdiameter = 0;
if(root == NULL)
{
*height = 0;
return 0; /* diameter is also 0 */
}
/* Get the heights of left and right subtrees in lh and rh
And store the returned values in ldiameter and ldiameter */
ldiameter = diameterOpt(root->left, &lh);
rdiameter = diameterOpt(root->right, &rh);
/* Height of current node is max of heights of left and
right subtrees plus 1*/
*height = max(lh, rh) + 1;
return max(lh + rh + 1, max(ldiameter, rdiameter));
}
Time Complexity: O(n)