简体   繁体   中英

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. 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. 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. Here is the displayTree() method.

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

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:

像树一样的文件管理器

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

屏幕截图,没有交叉节点

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