繁体   English   中英

二叉树节点-哪种方式?

[英]Binary Tree Nodes - Which Way?

对于分配给我们的数据结构,我们必须创建一个测试类来确定所给的代码是否正确地遍历了测试类中的二叉树。

这些是给我们的BinaryTreeNode类的3个构造函数:

public BinaryTreeNode(Object theElement, BinaryTreeNode theleftChild, BinaryTreeNode therightChild)
{
    element = theElement;
    leftChild = theleftChild;
    rightChild = therightChild;
}

public BinaryTreeNode(Object theElement)
{
    element = theElement;
}

public BinaryTreeNode() {} 

我在测试类中迅速进行了以下操作,以创建指定的树之一:

// tree for ( A - B ) / C
BinaryTreeNode b1 = new BinaryTreeNode("A");
BinaryTreeNode b2 = new BinaryTreeNode("-");
BinaryTreeNode b3 = new BinaryTreeNode("B");
BinaryTreeNode b4 = new BinaryTreeNode("/");
BinaryTreeNode b5 = new BinaryTreeNode("C");
BinaryTreeNode bAB = new BinaryTreeNode(b2, b1, b3);
BinaryTreeNode bRoot = new BinaryTreeNode(b4, bAB, b5);
q.put(bRoot);

但是,我的朋友建议我这样做:

// tree for ( A - B ) / C
BinaryTreeNode b1 = new BinaryTreeNode("A");
BinaryTreeNode b2 = new BinaryTreeNode("B");
BinaryTreeNode b3 = new BinaryTreeNode("C");
BinaryTreeNode bRoot= new BinaryTreeNode("/", new BinaryTreeNode("-", b1, b2), b3);
q.put(bRoot);

但是,他很难解释为什么这种方法更好。 谁能解释为什么这样更有效? 如果示例中需要更多代码,只需询问。

第二个使用字符串作为“元素”值,第一个使用BinaryTreeNode。 我不知道“元素”的值应该是什么,但是我的直觉说它应该是一个字符串。 这是这些片段之间的唯一区别。

这是一个混合袋;-)

就其输出而言,第二种方法似乎更好:
始终在BinaryTreeNode的element成员中放置一个字符串,因此第一种方法为此目的使用字符串和BinaryTreeNode实例的混合。

至少,我建议将第一个代码段重写为

BinaryTreeNode b1 = new BinaryTreeNode("A");
BinaryTreeNode b3 = new BinaryTreeNode("B");
BinaryTreeNode b5 = new BinaryTreeNode("C");
BinaryTreeNode bAB = new BinaryTreeNode("-", b1, b3);
BinaryTreeNode bRoot = new BinaryTreeNode("/", bAB, b5);

第二种方法的另一个优点是它不需要中间节点 (例如上面的bAB)的额外存储 这不是一个大问题,因为这些变量是引用类型,因此需要很少的存储并非常有效地进行复制。 第二种方法本质上是在原地构建这些节点 ,这可以被认为是效率更高的。 (也就是说,随着树的深度增加,尝试以这种方式创建所有中间节点将很快变得不可行...)

有一个有趣的停顿,一个教学时刻;-),我们在此思考过早优化的诱惑...

另一方面,第一种方法的优点(指示了语义变化)是,它使代码的支出更为规律 ,这可能有助于更轻松地定位树结构中的问题。
[编辑:]可能的混合解决方案是使用解决方案#2定义树的底部两层(叶节点及其上方的层),即每行最多定义三个节点。 这样做的好处是可以将定义树所需的行数大致减半(随着树的增长可能成为一个因素),并且不必为最多的节点(叶子-节点)。 现在...这样的结构/语法在/如果附加了树时灵活性要差很多,需要重新平衡等等。(也许这就是为什么老师建议对树进行硬编码,以便给让学生对重新平衡树所需的操作类型有“感觉”。)

这样说

两种方法都不是超级校准的。

稍凉的方法可能是从文本文件中读取树。 该文本中的语法可能非常接近方法1布局中明显的每行一个节点,因此有人可能会争辩说它本身并不会带来太大收益……也许只是节省了几次击键。 但是,当我们认为这种解决方案的优势将使 “数据”与“代码”解耦时,将变得更加明显 我们不需要重新编译程序(或使该二进制文件具有多个不同版本)即可在不同的树上运行,我们只需将程序指向不同的文本文件即可。 当/如果重构代码,比如说修改节点类的名称,这种去耦也变得很有趣。 在极端的情况下,此代码与数据的独立性将允许使用完全不同的树库,唯一必要的更改是在从文件中解析出节点的逻辑结构之后,生成一些逻辑来映射节点的构造和组装。

左边是第一个代码生成的结构,第二个代码在右边:

          * -- "/"            "/"
         / \                  / \
        /   \                /   \
"-" -- *    "C"            "-"   "C"
      / \                  / \
     /   \                /   \
   "A"   "B"            "A"   "B"

布丁的证据在于饮食:您想如何加工这种树? 在第二种情况下,您从根节点开始,读取其元素(如果它是运算符),则在适当时递归地读取子级,然后对其值执行运算符的功能。 但是,在第一种情况下,您不读取元素,而是先检查其类型-如果它是对另一个树节点的引用,则意味着它是一个运算符,因此您将该节点的值用作运算符。 这个结论“这是一个树节点,所以它是一个运算符”对您来说似乎有些可疑。 如果要对类型进行双补,则类型应具有含义,因此运算符应为“ operator”类型。 但是,对于本练习,我认为按字符串值进行分派就足够了。 结论:将运算符直接放入节点。

每个节点的元素本身不必是BinaryTreeNode。 任何任意对象都可以。

第二本书读起来更好,只有一件事。 如果您熟悉反向抛光符号,那么第二个符号的读取方式就像您输入RPN计算器一样。 考虑到这只是验证类功能的一项测试,我认为效率并不是真正的问题。

我是朋友,我的推理是将元素作为节点是不合适的,因为在这种情况下,我们使用它来表示数学方程式。 据我了解,您可以为一个单独的树指定一个根节点作为节点的元素,但这对于本示例来说是完全不合适的。

我以第一种方式看到的错误是,当他使用变量bAB(即bAB中的节点b1,b2和b3)时,他试图存储整个子树,我觉得这样做会错过使用树的意义。代表数学方程式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM