简体   繁体   中英

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. 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]).

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. Indices [17] - (alphaTree.length - 1) hold the right subtree.

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.

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:

- 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. The nodes are read into the array in the open() method.

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. 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.

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).

(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.)

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

(Posted on behalf of the 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). In other cases, I was skipping over nodes completely. This happened because of my use of the i variable in my for loops.

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. 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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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