如何获得二叉树的大小?

时间:2010-04-02 17:16:01

标签: c performance binary-tree

我有一个非常简单的二叉树结构,如:

struct nmbintree_s {
    unsigned int size;
    int (*cmp)(const void *e1, const void *e2);
    void (*destructor)(void *data);
    nmbintree_node *root;
};

struct nmbintree_node_s {
    void *data;
    struct nmbintree_node_s *right;
    struct nmbintree_node_s *left;
};

有时我需要从另一个树中提取“树”,我需要获取“提取树”的大小,以便更新初始“树”的大小。

我在考虑两种方法:

1)使用递归函数,例如:

unsigned int nmbintree_size(struct nmbintree_node* node) {
  if (node==NULL) {
    return(0);
  } 
  return( nmbintree_size(node->left) + nmbintree_size(node->right) + 1 );
} 

2)迭代方式(使用堆栈/队列)+对节点进行计数的前序/顺序/后序遍历。

您认为哪种方法更具“内存故障证明”/性能?

还有其他建议/提示吗?

注意:我可能会在将来对我的小项目使用此实现。所以我不想意外失败:)。

3 个答案:

答案 0 :(得分:5)

只需使用递归函数。以这种方式实现起来很简单,并且不需要使其更加复杂化。

如果您“手动”执行此操作,您基本上最终会实现相同的操作,只是您不会将系统调用堆栈用于临时变量,而是使用您自己的堆栈。通常,这将没有任何优势超过更复杂的代码。

如果你后来发现程序中花费了大量时间来计算树的大小(这可能不会发生),你仍然可以开始分析事物并尝试手动实现的执行方式。但是,最好还是进行算法改进,比如在提取过程中已经跟踪了大小的变化。

答案 1 :(得分:2)

如果你的“非常简单”的二叉树不平衡,那么递归选项是可怕的,因为无约束的递归深度。迭代遍历具有相同的时间问题,但至少堆栈/队列在您的控制之下,因此您不需要崩溃。实际上,通过每个节点中的标志和一个额外的指针以及独占访问,您可以在没有任何堆栈/队列的情况下迭代树。

另一个选项是每个节点存储它下面的子树的大小。这意味着无论何时添加或删除某些内容,您都必须一直跟踪更新所有大小的根。因此,如果树不平衡,这将是一个沉重的操作。

如果树是平衡的,那么它不是很深。所有选项都是防故障的,并且性能是通过测量来估计的:-)但是基于你的树节点结构,要么它不平衡,要么就是你在玩指针最低位的标记玩傻游戏......

这可能没有多大意义。对于二叉树的许多实际用途(特别是如果它是二进制搜索树),您很快就会意识到它希望它能够平衡。因此,当你达到这一点时,请节省你的精力: - )

答案 2 :(得分:1)

这棵树有多大,你需要多久知道它的大小?正如......所说,递归函数是最简单的,可能是最快的。

如果树类似于10 ^ 3个节点,并且每秒更改10 ^ 3次,那么您可以保留一个外部计数,当您删除节点时会减少该计数,并在添加节点时递增。除此之外,简单是最好的。

就个人而言,我不喜欢任何需要使用额外信息(如计数和“向上”指针)来装饰节点的解决方案(尽管有时候我会这样做)。任何类似的额外数据都会使结构非规范化,因此更改它会涉及额外的代码和额外的错误机会。