简体   繁体   English

二叉树:某些子节点为空,其他则不为

[英]Binary-Tree: Some Child Nodes Null, Others Not

I'm writing a program that converts to Morse code or vice versa. 我正在写一个程序,可以转换为莫尔斯电码,反之亦然。 I use a tree for more efficent searching of codes or associated values. 我使用树来更有效地搜索代码或关联值。 The Morse and associated values are read into a static array from a file. Morse和关联的值将从文件读取到静态数组中。 Index 0 is the root of all the other subtrees and is actually a dummy node that links to the left subtree (index[1]) and the right subtree (index[16]). 索引0是所有其他子树的根,实际上是一个虚拟节点,链接到左子树(index [1])和右子树(index [16])。

After reading in the nodes, I link the children nodes by looping through the static array and assigning the nodes as I go. 读完节点后,我通过遍历静态数组并按需分配节点来链接子节点。 Indices [2] - [16] hold the left subtree. 索引[2]-[16]保留左子树。 Indices [17] - (alphaTree.length - 1) hold the right subtree. 索引[17]-(alphaTree.length-1)保留右侧的子树。

Here's my problem: when trying to assign all the child nodes, some of them, when I print them out, are null. 这是我的问题:当尝试分配所有子节点时,当我将它们打印出来时,其中的一些为空。 The nodes themselves aren't null, just the children. 节点本身不是null,而只是子节点。

I notice a pattern, but can't figure out how to fix it. 我注意到了一种模式,但不知道如何解决。

Below is sample output. 下面是示例输出。 The output is big, so I cut it down, but left enough so you can see what I mean: 输出很大,因此我将其削减了,但留得足够多,您可以看到我的意思:

Element left 0: -, t
Element right 0: *, e
Element left 1: null
Element right 1: null
Element left 2: --, m
Element right 2: null
Element left 3: null
Element right 3: -*, n
Element left 4: ---, o
Element right 4: null
Element left 5: null

. . .

Element right 25: null
Element left 26: null
Element right 26: *-**, l
Element left 27: **--, ö
Element right 27: null
Element left 28: null
Element right 28: **-*, f
Element left 29: ***-, v
Element right 29: null

Following is the file I use to fill the static array. 以下是我用来填充静态数组的文件。 Because there are special characters in the tree, I use ASCII and convert as I read the file: 因为树中有特殊字符,所以我使用ASCII并在读取文件时进行转换:

- 116
-- 109
-* 110
--- 111
--* 103
-*- 107
-** 100
---- 247 
---* 246
--*- 113
--** 122
-*-- 121
-*-* 99
-**- 120
-*** 98
* 101
*- 97
** 105
*-- 119
*-* 114
**- 117
*** 115
*--- 106
*--* 112
*-*- 228
*-** 108
**-- 246
**-* 102
***- 118
**** 104

Below is the code I use to populate the tree and link the nodes. 下面是我用来填充树并链接节点的代码。 linkLeftTree() and linkRightTree() are the methods that link parent nodes with their children nodes. linkLeftTree()和linkRightTree()是将父节点与其子节点链接的方法。 The nodes are read into the array in the open() method. 通过open()方法将节点读入数组。

package MorseTrees;

import MorseTrees.Nodes.*;
import java.util.*;
import java.io.*;

public class TreePopulater {
    private static final int ALPHABET = 31;
    private static final String alphaRaw = "alphatree2.txt";    
    private static final A_Node[] alphaTree = new AlphaNode[ALPHABET];
    private A_Node aNode;

    public TreePopulater() {
        alphaTree[0] = new AlphaNode("000");
        alphaTree[0].setAlpha('0'); 
        populateRaw(alphaRaw);
    }

    private A_Node[] populateRaw(String treeType)
    {   
        // open and fill static array
        open(treeType);
    }

    private void open(String fileName) {

        //try, catch, etc.
        Scanner in = new Scanner(new File(fileName));
     int counter = 1;

   while (in.hasNextLine()) {
      aNode = new AlphaNode(in.next());
      aNode.setAlpha((char) in.nextInt());
           alphaTree[counter] = aNode;

      counter++;
   }

        linkNodes();
    }

    private void linkNodes() {  
        // force link root node 
        alphaTree[0].setLeft(alphaTree[1]);
        alphaTree[0].setRight(alphaTree[16]);

        linkLeftTree();
        linkRightTree();
        printChildren();
    }

    public void linkLeftTree()
    {
        // link the left, or first half, of the array
        for (int i = 2; i < (alphaTree.length / 2); i++) // or 16
        {   
            alphaTree[i].setLeft(alphaTree[(i++)]);
            alphaTree[i].setRight(alphaTree[(i)]);
        }
    }

    public void linkRightTree()
    {
        // link the right, or second half, of the array
        for (int i = 17; i <= alphaTree.length - 1; i++)
        {
            alphaTree[i].setLeft(alphaTree[(i++)]);
            alphaTree[i].setRight(alphaTree[(i)]);  
        }   
    }

    public void printChildren()
    {
        for (int i = 0; i < alphaTree.length - 1; i++)
        {
            System.out.println("Element left " + i + ": " + alphaTree[i].leftChild());
            System.out.println("Element right " + i + ": " + alphaTree[i].rightChild());
        }   
    }

    public static void main(String[] args)
    {
        TreePopulater tp = new TreePopulater();
    }
}

The node class, AlphaNode, extends A_Node. 节点类AlphaNode扩展了A_Node。 A_Node looks like you'd expect it: instance variables for right and left children, for the morse code and the letter associated with it, and all the getters and setters needed. A_Node看起来就像您期望的那样:左右两个孩子的实例变量,莫尔斯电码和与其关联的字母以及所有所需的getter和setter方法。

Weirdly enough, if I use a System.out.println() on the setters in linkLeftTree() and linkRightTree(), I see no nulls while in the loop, but still have nulls when I actually try to access children nodes (like in a preorder search, for example). 奇怪的是,如果我在linkLeftTree()和linkRightTree()中的setter上使用System.out.println(),则在循环中看不到任何空值,但是当我实际尝试访问子节点时仍然有空值(例如例如,预订搜索)。

(Credit where credit is due: the alphabet tree implemented in this program is based on Charles Petzold's optimized tree in the book, "Code". But all the code here was written by yours truly.) (应归功于信贷:该程序中实现的字母树是基于Charles Petzold在“代码”一书中优化的树。但是这里的所有代码都是您真正编写的。)

I am doubtful about the following code: 我对以下代码表示怀疑:

   public void linkLeftTree()
    {
        // link the left, or first half, of the array 
        // NOTE: the code runs for i=2,4,8,10,12,14 so many nodes have the left
        //      and right neighbors unassigned
        for (int i = 2; i < (alphaTree.length / 2); i++) // or 16
        {   // NOTE:
            // This should alphaTree[i].setLeft(alphaTree[i+1])
            // Since you are changing the value of i twice 
            // A good idea is to print i and verify the values
            alphaTree[i].setLeft(alphaTree[(i++)]);
            alphaTree[i].setRight(alphaTree[(i)]);
        }
    }

    public void linkRightTree()
    {
        // link the right, or second half, of the array
        //NOTE: the code runs for i=17,19.. so many nodes have the left
        //      and right neighbors unassigned
        for (int i = 17; i <= alphaTree.length - 1; i++)
        {
            // Same as above
            alphaTree[i].setLeft(alphaTree[(i++)]);
            alphaTree[i].setRight(alphaTree[(i)]);  
        }   
    }

I'm not exactly sure what indexes would be specific to your algorithm but I think I answered your question related to the nulls appearing. 我不完全确定哪种索引将特定于您的算法,但我想我回答了您的问题,涉及出现的空值。

All the best with the assignment though! 祝您工作顺利! It's great that you are working it out on your own..:-) 自己解决这个问题真是太好了.. :-)

V V

(Posted on behalf of the OP) . (代表OP张贴)

I changed the printChildren() method to also print out the parent nodes, and realized that I was assigning the parents themselves as their own children (ex: n became the child of n). 我更改了printChildren()方法以也打印出父节点,并意识到我正在将父节点本身分配为自己的子节点(例如:n成为n的子节点)。 In other cases, I was skipping over nodes completely. 在其他情况下,我完全跳过了节点。 This happened because of my use of the i variable in my for loops. 发生这种情况是因为我在for循环中使用了i变量。

The code below has solved the problem and does exactly what I want. 下面的代码已解决了该问题,并且正是我想要的。 It's a hideous, inelegant hack, but when I go back to refactor it, I'll figure out how to make it cleaner. 这是一个骇人听闻的,微不足道的骇客,但是当我回去重构它时,我会想出如何使它更整洁的方法。 The solution came in the linkLeftTree() and linkRightTree() methods. 解决方案来自linkLeftTree()和linkRightTree()方法。 I realized that I wasn't supposed to assign children nodes to the leaves, so I cut down on the number of nodes I looped through in both cases and used counters to assign the children. 我意识到我不应该为叶子分配子节点,因此在两种情况下我都减少了循环遍历的节点数量,并使用计数器分配了子节点。

public void linkLeftTree() {    
    int counter = 2;
    int counter2 = 3;

        // link the left, or first half, of the array

    for (int i = 1; i < 8; i++) {   
    alphaTree[i].setLeft(alphaTree[(counter++)]);
    alphaTree[i].setRight(alphaTree[(counter2++)]);

              if (counter <= 13) {
         counter++;
             counter2++;
    }
    }
}

public void linkRightTree() {
    int counter = 16;
    int counter2 = 17;

    // link the right, or second half, of the array
    for (int i = 16; i < (24); i++) {   
        alphaTree[i].setLeft(alphaTree[(counter++)]);
        alphaTree[i].setRight(alphaTree[(counter2++)]);

        if (counter < 29) { 
            counter++;
            counter2++;
        }
    }
}

My recursive searches and prints are working as expected as well, and I'm pretty much done writing the program. 我的递归搜索和打印也按预期工作,并且编写程序几乎完成了。 Now begins the process of cleaning it up. 现在开始清理它的过程。 Thanks to everyone who took the time to look at this! 感谢所有花时间研究此问题的人!

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

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