二叉树:一些子节点空,其他没有

时间:2012-06-11 01:27:54

标签: java binary-tree

我正在编写一个转换为摩尔斯电码的程序,反之亦然。我使用树来更有效地搜索代码或相关值。莫尔斯和关联值从文件读入静态数组。索引0是所有其他子树的根,实际上是一个链接到左子树(索引[1])和右子树(索引[16])的虚节点。

在节点中读取之后,我通过循环遍历静态数组并按照我的方式分配节点来链接子节点。指数[2] - [16]持有左子树。指数[17] - (alphaTree.length - 1)保持正确的子树。

这是我的问题:当尝试分配所有子节点时,其中一些,当我打印出来时,它们是空的。节点本身不是空的,只是孩子们。

我注意到一种模式,但无法弄清楚如何修复它。

以下是示例输出。输出很大,所以我把它剪下来,但留下足够让你可以看到我的意思:

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

以下是我用来填充静态数组的文件。因为树中有特殊字符,所以我使用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

下面是我用来填充树和链接节点的代码。 linkLeftTree()和linkRightTree()是将父节点与其子节点相链接的方法。节点在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();
    }
}

节点类AlphaNode扩展了A_Node。 A_Node看起来像你期望的那样:右边和左边的孩子的实例变量,摩尔斯电码和与之相关的字母,以及所需的所有getter和setter。

奇怪的是,如果我在linkLeftTree()和linkRightTree()中的setter上使用System.out.println(),我在循环中看到没有空值,但在我实际尝试访问子节点时仍然有空值(例如在预购搜索中)。

(信用到期的信用:本程序中实施的字母树基于Charles Petzold在本书中的优化树,&#34; Code&#34;。但这里的所有代码都是由您自己编写的真正。)

2 个答案:

答案 0 :(得分:0)

我怀疑以下代码:

   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)]);  
        }   
    }

我不确定哪些索引特定于您的算法,但我想我已经回答了与出现的空值相关的问题。

尽管如此,这一切都是最好的!你自己解决这个问题真是太好了..: - )

V

答案 1 :(得分:0)

(代表OP发布)

我更改了printChildren()方法以打印出父节点,并意识到我将父母自己分配为自己的子节点(例如:n成为n的子节点)。在其他情况下,我完全跳过节点。这是因为我在for循环中使用了i变量。

下面的代码已经解决了问题并完全符合我的要求。这是一个可怕的,不优雅的黑客,但当我回去重构它时,我会弄清楚如何让它变得更干净。解决方案来自linkLeftTree()和linkRightTree()方法。我意识到我不应该将子节点分配给叶子,因此我减少了在两种情况下循环的节点数量,并使用计数器来分配子节点。

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++;
        }
    }
}

我的递归搜索和打印工作也按预期工作,而且我已经完成了编写程序。现在开始清理它的过程。感谢所有花时间看这个的人!