Here is my code, there are three classes and they are separated by the code blocks. There is a: Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at project3.Main.lambda$0(Main.java:81)
error in my code and I am not sure how to fix it.
package project3;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
public class Main extends JFrame {
private JTextField input = new JTextField(20), output = new JTextField(30);
private static BinaryTree inputTree;
//main here
public static void main(String[] args) {
Main frame = new Main();
frame.setVisible(true);
}
//===================================================================================
// Class constructor creates GUI with three panels (input, buttons, and output)
//===================================================================================
public Main() {
super("Binary Tree Categorizer");
setSize(715, 175);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(3, 1));
JComponent[] inputComponents = {new JLabel("Enter Expression"), input};
JComponent[] outputComponents = {new JLabel("Output"), output};
JButton[] buttonComponents = {new JButton("Make Tree"), new JButton("Is Balanced?"),
new JButton("Is Full?"), new JButton("Is Proper?"), new JButton("Height"),
new JButton("Nodes"), new JButton("Inorder")};
makeFlowPanel(inputComponents);
makeFlowPanel(buttonComponents);
makeFlowPanel(outputComponents);
addActionListeners(buttonComponents);
output.setEditable(false);
setResizable(false);
}
//================================================================================================
// Creates a flow panel from array of components. Borrowed the idea for this method from Prof Jarc
//================================================================================================
private void makeFlowPanel(JComponent[] components) {
JPanel panel = new JPanel(new FlowLayout());
for (Component component: components) { panel.add(component); }
add(panel);
}
//================================================================================================
// Adds the ActionListener to the array of buttons passed to it, similar to previous
//================================================================================================
private void addActionListeners (JButton[] buttons){
for (JButton button: buttons){
button.addActionListener(treeListener);
}
}
//========================================================================================================
// ActionListener uses switch statement to set output text based on String returned from getActionCommand
//========================================================================================================
private final ActionListener treeListener = event -> {
try {
switch ((event.getActionCommand())){
case "Make Tree":
inputTree = new BinaryTree(input.getText());
output.setText(inputTree.toString());
break;
case "Is Balanced?":
output.setText(String.valueOf(inputTree.isBalanced()));
break;
case "Is Full?":
output.setText(String.valueOf(inputTree.isFull()));
break;
case "Is Proper?":
output.setText(String.valueOf(inputTree.isProper()));
break;
case "Height":
output.setText(String.valueOf(inputTree.height()));
break;
case "Nodes":
output.setText(String.valueOf(inputTree.nodes()));
break;
case "Inorder":
output.setText(inputTree.inOrder());
break;
}
} catch (InvalidTreeSyntax except) {
JOptionPane.showMessageDialog(getParent(),except.getMessage());
}catch (IndexOutOfBoundsException indexExcept) {
JOptionPane.showMessageDialog(getParent(),"No input given!");
}
};
}
package project3;
public class Node {
private String info;
private Node left;
private Node right;
public Node(String info) {this.info = info;}
private void addChild(Node child) throws InvalidTreeSyntax{
if(this.left == null){this.setLeft(child); }
else if(this.right == null){this.setRight(child);}
else{throw new InvalidTreeSyntax("Nodes can only have 2 children!");}}
//setters for the nodes
private void setLeft(Node newLeft){left = newLeft;}
private void setRight(Node newRight){right = newRight;}
@Override //calls the recursive method
public String toString(){ return toString(this);}
//recursivley printing out the nodes
private static String toString(Node root){
return(root == null) ? "" : "("+ root.info + toString(root.left) + toString(root.right)+ ")";
}
}
package project3;
public class InvalidTreeSyntax extends Exception{
public InvalidTreeSyntax(){
super();
}
public InvalidTreeSyntax(String message){
super(message);
}
}
package project3;
import java.util.EmptyStackException;
import java.util.Stack;
public class BinaryTree {
Node parent, child; //parent is now synonymous with root
//===================================================================================================
//BianaryTree constructor: Takes the input string and stores it as an array based on the parenthesis
// loops through using a stack and adds children that fall within the parental parenthesis
//===================================================================================================
public BinaryTree(String input) throws InvalidTreeSyntax{
Stack<Node> nodeStack = new Stack<>();
String[] inputArray = input.substring(1, input.length()-1)
.split("(?<=\\()|(?=\\()|(?<=\\))|(?=\\))");
parent = new Node(inputArray[0]);
for(int i= 1;i<inputArray.length-1;i++){
if(inputArray[i].equals("(")){nodeStack.push(parent);
if(child != null){parent = child;}
}else if(inputArray[i].equals(")")){
try{child = parent; parent = nodeStack.pop();
}catch(EmptyStackException emptyStack){throw new InvalidTreeSyntax("Incorrect parenthesis!");}
}else{child = new Node(inputArray[i]);
if(parent != null){parent.addChild(child);}
}
}
if(this.recNodes(parent)* 3 != input.length()) throw new InvalidTreeSyntax("Incorrect Syntax!");
}
//===================================================================================================
//checkBalanced: must determine that the absolute difference between the branches is max at 1
//will call the recursive method and will also cal recursive height method
//===================================================================================================
public boolean isBalanced(){return recIsBalanced(this.parent);}
private boolean recIsBalanced(Node root){
//base case
if(root == null){
return true;
}
return (Math.abs(recHeight(root.left)- recHeight(root.right)) <=1) &&
(recIsBalanced(root.left) && recIsBalanced(root.right));
}
//===================================================================================================
//checkFull: determines if height has the maximum nodes
//calls recursive and recursive height method
//===================================================================================================
public boolean isFull() {return recIsFull(this.parent, recHeight(this.parent), 0);}
private boolean recIsFull(Node root, int height, int index){
if(root == null){return true;}
if(root.left == null && root.right == null){return (height == index +1);}
if(root.left == null || root.right == null){return false;}
return recIsFull(root.left, height, index+1) && recIsFull(root.right, height, index+1);
}
//===================================================================================================
//isProper: determines if each node has 2 or zero childern in the tree
//just calls the recursive method
//===================================================================================================
public boolean isProper(){return recIsProper(this.parent);}
private boolean recIsProper(Node root){
if(root == null){return true;}
return((root.left != null || root.right ==null)&&(root.left == null|| root.right != null))
&&(recIsProper(root.left)&& recIsProper(root.right));
}
//===================================================================================================
//height: finds the height of bianary trees which have a root node of 0
//calls the recursive method
//===================================================================================================
public int height(){return recHeight(this.parent)-1;}
private int recHeight(Node root){
return(root == null)? 0: 1 +Math.max(recHeight(root.left), recHeight(root.right));
}
//===================================================================================================
//nodes: finds the amount of nodes in a bianary tree
//uses the recursive method that will add one for every node of the left and right subtree,
//it will be 0 if null
//===================================================================================================
public int nodes(){return recNodes(this.parent);}
private int recNodes(Node root){
return (root == null)? 0 : 1+ recNodes(root.left)+ recNodes(root.right);
}
//===================================================================================================
//inOrder: onfo of nodes is written in bianary tree order
//recursive method called, uses algorithm: left to root to right
//===================================================================================================
public String inOrder(){
return recInOrder(this.parent);
}
private String recInOrder(Node root){
return(root == null)? "" : "(" + recInOrder(root.left) + root.info + recInOrder(root.right)+ ")";
}
@Override
public String toString(){ return parent.toString(); }
//===================================================================================================
//Nested node class/ arguments:
//
//===================================================================================================
public static class Node{
private String info;
private Node left;
private Node right;
public Node(String info){ this.info = info;}
private void addChild(Node child) throws InvalidTreeSyntax{
if(this.left == null){this.setLeft(child);}
else if(this.right == null){ this.setRight(child);}
else{throw new InvalidTreeSyntax("Nodes can only have 2 childern!");}}
private void setLeft(Node newLeft){left = newLeft;}
private void setRight(Node newRight){right = newRight;}
@Override
public String toString(){return toString(this);}
private static String toString(Node root){
return(root == null) ? "" : "(" + root.info + toString(root.left) + toString(root.right) + ")";
}
}
}
In addition, the program should allow the user to request that each of the following features of the tree be displayed:
- The height of the tree. The height of a tree is the maximum level of all of its nodes. The root node containing A is at the level 0. Because all three leaf nodes in the above tree are at level 2, its height is 2.
- The number of nodes in the tree. As previously mentioned, the above tree has 6 nodes.
- An fully parenthesized inorder traversal of the tree. The following should be displayed as the inorder traversal of the above tree: ((( j ) G ( 1 )) A (( 5 ) z )) The third programming project involves writing a program that allows the user to enter a binary tree in a parenthesized prefix format and then allows it to be categorized and allows various features of that tree to be displayed. An example of a tree written in the input format is the following: (A(G(j)(1))(z(5))) In the above example, data in each node of the tree contains a single alphanumeric character. No spaces are permitted. Each tree is enclosed in parentheses. Inside those parentheses, after the single character are either zero, one or two subtrees also enclosed in parentheses. When only one subtree is present, it is the left subtree and when two are present, they represent the left and right subtrees.
This project consist of three classes. The main class should create a GUI that allows the user to input a tree in the above described format and then construct the tree once the Make Tree button is clicked. The GUI should look as follows: The GUI must be generated by code that you write. You may not use a drag-and-drop GUI generator. The second class should be the BinaryTree class, which should contain a static nested class to define the nodes of the binary tree, together with a constructor that is called when the Make Tree button is clicked and is supplied the string representation of the tree and constructs the actual tree from that string. In addition, it should have public methods that are called when each of the remaining six buttons are clicked. All of those public methods should have corresponding private methods that accomplish their tasks using recursion. The third class should be named InvalidTreeSyntax, which defines a checked exception. It should be thrown when a invalid string is supplied and the Make Tree button is clicked. It should be caught in the main class and a JOptionPane window should be displayed that describes the reason for the invalid syntax.
What the GUI looks like: [My code creates the GUI but does not let a response appear] (https://i.stack.imgur.com/UcC58.png)