二叉树中心

时间:2011-08-17 14:50:23

标签: c algorithm binary-tree center

我们怎样才能找到二叉树的中心? 什么是最有效的算法。虽然二叉树的中心将是与树的直径相对应的路径的中点。我们可以在不知道路径的情况下找到树的直径,是否有找到二叉树中心的类似技术?

3 个答案:

答案 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)