简体   繁体   English

二叉树中的节点交叉

[英]Nodes crossing in Binary Tree

I am working on code to build a binary tree and display it for a homework assignment.(So, naturally, I have to build the tree from scratch.) The code functions, however I can't seem to figure out a way to keep the nodes from crossing about 4 levels down the tree. 我正在研究代码以构建二叉树并显示它以进行家庭作业。(因此,自然地,我必须从头开始构建树。)代码功能,但是我似乎想不出一种方法来保持节点从树上越过大约4个级别。 I'm hoping someone can help kick start my brain... but is there a way to check how many levels the tree is down and adjust the horizontal distance between nodes of the levels above? 我希望有人可以帮助我动动脑筋...但是有没有办法检查树倒下多少层并调整上面各层节点之间的水平距离? In my research I've seen a few done differently, but mine has to be recursively with the displayTree() method, per the assignment parameters. 在我的研究中,我看到了一些不同的方法,但是根据分配参数,必须使用displayTree()方法来递归地进行操作。 Any help is appreciated. 任何帮助表示赞赏。

PS the current horizontalGap variable is what I've been tinkering with so if it messes with the code, I apologize. PS:当前的horizo​​ntalGap变量是我一直在修改的,因此,如果它与代码混淆,我深表歉意。 Here is the displayTree() method. 这是displayTree()方法。

//displayTree() with crossing issue
//**************************************************************************
public void displayTree(Graphics g, Node localTree, int x, int y, int level)

{
      // Display the root
      int verticalGap = 50;
      int horizontalGap = 250 / level;

      g.drawOval(x, y, radius, radius);
      g.drawString(localTree.getKey() + "", x + (radius / 4) , y + 20);

      if (localTree.getLeft() != null) {
         // Draw a line to the left node
         lineToLeftChild(g, x - horizontalGap, y + verticalGap, x, y);
        // Draw the left subtree recursively
         displayTree(g, localTree.leftChild, x - horizontalGap, y + verticalGap, level + 1);
      }

     if (localTree.rightChild != null) {
         // Draw a line to the right node
        lineToRightChild(g, x + horizontalGap, y + verticalGap, x, y);
        // Draw the right subtree recursively
        displayTree(g, localTree.rightChild, x + horizontalGap, y + verticalGap, level + 1);  
      }
    }//end displayTree()
    //**************************************************************************

    //Line to child
    //**************************************************************************
    private void lineToLeftChild(Graphics g,  int x1, int y1, int x2, int y2) { 
        g.drawLine(x1 + (radius/2), y1, x2, y2 + (radius/2));  
    }//end LinetoLeft
    //**************************************************************************

    //Line to child
    //**************************************************************************
    private void lineToRightChild(Graphics g, int x1, int y1, int x2, int y2) {
        g.drawLine(x1 + (radius /2), y1, (x2 + radius) , y2 + (radius/2));
    }//end line to Right()
    //**************************************************************************
}  

This is an example of your issue with crossing nodes? 这是您遇到交叉节点问题的一个示例吗?

带有交叉节点的屏幕截图

I think that the fact that your nodes start crossing at some level is a consequence of how you display your tree. 我认为您的节​​点开始在某个级别交叉的事实是您如何显示树的结果。 The number of nodes at a lower level can be much higher that at a higher level, so the minimum amount of space needs to be determined at the level that has the highest number of nodes. 较低级别的节点数量可以比较高级别的节点数量高得多,因此需要在具有最高节点数量的级别上确定最小的空间量。 That can lead to a lot of white space at the higher levels. 这会在较高级别上导致大量空白。

How many levels do you want to support? 您要支持多少个级别? You could calculate the minimum space for the maximum amount of nodes at a certain level (like 10 pixels for 2^6 = 64 nodes for 6 levels beneath the root node) and double the space for each higher level. 您可以计算某个级别上最大数量的节点的最小空间(例如,根节点下6个级别的2 ^ 6 = 10个像素= 64个节点),每个更高级别的空间则加倍。

You can also use a different way to display your tree, like this "file manager" like approach from The Java Tutorials - How to Use Trees , where the child nodes take up just as much space as they need: 您还可以使用其他方式显示树,例如The Java Tutorials-How to Use Trees中的“文件管理器”之类的方法,在该方法中,子节点占用所需的空间就足够了:

像树一样的文件管理器

Edit: code example 编辑:代码示例

If you want to get good and quick answers from Stack Overflow, it is a great idea to add a short, runnable example of your issue to your question (a socalled Minimal, Complete, and Verifiable example: see https://stackoverflow.com/help/mcve for more information). 如果您想从Stack Overflow上获得好的和快速的答案,最好在问题中添加一个简短,可运行的问题示例(所谓的Minimal,Complete和Verifiable示例:请参见https://stackoverflow.com / help / mcve了解更多信息)。 This way you help others to help you. 这样,您可以帮助他人来帮助您。

This is some code I added to your code to create an example with a possible solution: 这是我添加到您的代码中的一些代码,以创建具有可能解决方案的示例:

// Main class TreeFromScratch:

import java.awt.BorderLayout;
import javax.swing.*;

public class TreeFromScratch {
    public static void main(final String[] arguments) {
        SwingUtilities.invokeLater(() -> new TreeFromScratch().createAndShowGui());
    }

    private void createAndShowGui() {
        final JFrame frame = new JFrame("Stack Overflow");
        frame.setBounds(100, 100, 1200, 600);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        final JPanel panel = new JPanel(new BorderLayout());
        final Node tree = createTree();
        panel.add(new CustomTree(tree), BorderLayout.CENTER);
        frame.getContentPane().add(panel);

        frame.setVisible(true);
    }

    private Node createTree() {
        final Node tree = new Node('a');
        tree.leftChild = new Node('b');

        tree.leftChild.leftChild = new Node('c');
        tree.leftChild.leftChild.leftChild = new Node('d');
        tree.leftChild.leftChild.leftChild.leftChild = new Node('e');
        tree.leftChild.leftChild.leftChild.leftChild.leftChild = new Node('f');

        tree.leftChild.rightChild = new Node('g');
        tree.leftChild.rightChild.rightChild = new Node('h');
        tree.leftChild.rightChild.rightChild.rightChild = new Node('i');
        tree.leftChild.rightChild.rightChild.rightChild.rightChild = new Node('j');

        tree.rightChild = new Node('k');
        tree.rightChild.leftChild = new Node('l');
        tree.rightChild.leftChild.leftChild = new Node('m');
        tree.rightChild.leftChild.leftChild.leftChild = new Node('n');
        tree.rightChild.leftChild.leftChild.leftChild.leftChild = new Node('o');

        return tree;
    }
}


// Class CustomTree:

import java.awt.Graphics;
import javax.swing.JPanel;

public class CustomTree extends JPanel {
    private Node tree;
    private int radius = 40;

    public CustomTree(Node tree) {
        this.tree = tree;
    }

    @Override
    protected void paintComponent(Graphics g) {
        displayTree(g, tree, 660, 100, 1);
    }

    //displayTree() with crossing issue
    //**************************************************************************
    public void displayTree(Graphics g, Node localTree, int x, int y, int level) {
        // Display the root
        int verticalGap = 50;
        //int horizontalGap = 250 / level;
        int horizontalGap = (int) (660 / Math.pow(2, level));

        g.drawOval(x, y, radius, radius);
        g.drawString(localTree.getKey() + "", x + (radius / 4), y + 20);

        if (localTree.getLeft() != null) {
            // Draw a line to the left node
            lineToLeftChild(g, x - horizontalGap, y + verticalGap, x, y);
            // Draw the left subtree recursively
            displayTree(g, localTree.leftChild, x - horizontalGap, y + verticalGap,
                        level + 1);
        }

        if (localTree.rightChild != null) {
            // Draw a line to the right node
            lineToRightChild(g, x + horizontalGap, y + verticalGap, x, y);
            // Draw the right subtree recursively
            displayTree(g, localTree.rightChild, x + horizontalGap, y + verticalGap,
                        level + 1);
        }
    }//end displayTree()
    //**************************************************************************

    //Line to child
    //**************************************************************************
    private void lineToLeftChild(Graphics g, int x1, int y1, int x2, int y2) {
        g.drawLine(x1 + (radius / 2), y1, x2, y2 + (radius / 2));
    }//end LinetoLeft
    //**************************************************************************

    //Line to child
    //**************************************************************************
    private void lineToRightChild(Graphics g, int x1, int y1, int x2, int y2) {
        g.drawLine(x1 + (radius / 2), y1, (x2 + radius), y2 + (radius / 2));
    }//end line to Right()
    //**************************************************************************
}


// Class Node:

public class Node {
    private char key;
    protected Node leftChild;
    protected Node rightChild;

    public Node(char key) {
        this.key = key;
    }

    public char getKey() {
        return key;
    }

    public Node getLeft() {
        return leftChild;
    }
}

With the different way to calculate horizontalGap , the tree now looks like this: 用不同的方法来计算horizontalGap ,树现在看起来像这样:

屏幕截图,没有交叉节点

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

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