BST String Traversal - java

I'm trying to implement an inorder, preorder, and postorder traversal algorithm for my BST. It seems that the inorder algorithm is working so far, but it's only returning the first character of the word. I realize that I'm returning char c, but I'm confused on how I would make it return the entire word. Any help would be highly appreciated!
package main;
import java.io.*;
import java.util.*;
// Node class
class Node
{
char c;
boolean end;
Node left, right;
public Node(char c)
{
this.c = c;
this.end = false;
this.left = null;
this.right = null;
}
}
class BinarySearchTree
{
private Node root;
public BinarySearchTree()
{
root = null;
}
public void addValue(String s)
{
root = addValue(root, s, 0);
}
private Node addValue(Node x, String s, int d)
{
char c = s.charAt(d);
if (x == null)
x = new Node(c);
if (c < x.c)
x.left = addValue(x.left, s, d);
else if (c > x.c)
x.right = addValue(x.right, s, d);
else x.end = true;
return x;
}
public boolean search(String s)
{
return search(root, s, 0);
}
private boolean search(Node x, String s, int d)
{
if (x == null)
return false;
char c = s.charAt(d);
if (c < x.c)
return search(x.left, s, d);
else if (c > x.c)
return search(x.right, s, d);
else
return x.end;
}
public void inorder(){
inorder(root);
}
private void inorder(Node r){
if (r != null){
inorder(r.left);
System.out.print(r.c);
inorder(r.right);
}
}
}
public class Project2
{
public static void main(String[] args) throws Exception
{
BinarySearchTree tree = new BinarySearchTree(); // Make new BST object
// Variable for scanned word
String token = "";
// Use scanner for input file
Scanner scan = new Scanner(new File("10words.txt")).useDelimiter("\\s+");
//Check for next line in text file
while (scan.hasNext())
{
token = scan.next();
tree.addValue(token);
}
scan.close();
tree.inorder();
Scanner inputWord = new Scanner(System.in);
System.out.print("\nEnter a word to search: ");
String word = inputWord.next().toLowerCase();
if(tree.search(word) == false){
System.out.println("Word NOT Found!");
} else{
System.out.println("Word Found!");
}
inputWord.close();
}
}

I did not look at your inorder code but you said it works so I'll believe you.
However I did take a look at your addValue code and you only save the first character here. No wonder you can't get the entire word back, you just don't save it :P
Instead, you should change your Node class to accept a String instead of a character. You won't need the d parameter in your addValue method then either.
The Java String class provides the .compareTo () method in order to lexicographically compare Strings. You can use it with string.compareTo(otherString)
This method will return a value < 0, equal to 0 or > 0.
< 0 means string is lexicographically smaller than otherString (for example: "Apple" would be smaller than "Banana")
= 0 means it's the exact same word
> 0 means string is bigger than otherString (for example: "Banana" would be bigger than "Apple")

your addValue method looks like it is incorrect. it only modifies the root, then character will be equal, so it returns. In particular d is never modified.
On a more fondamental level, a BST would be appropriate to look for a character in a tree, not for looking for a String. If you want to look for a word, you can use a Trie instead (which is not a binary tree).

Related

What is causing the Java Class Cast Exception Error? [duplicate]

This question already has answers here:
Explanation of ClassCastException in Java
(12 answers)
Closed 2 years ago.
My professor is having us implement Java comparable interfaces to help my Binary Search Tree compare word objects that hold the word that was scanned and then compare that word to other words, but for whatever reason, the second one I am doing is throwing an error. I do know that the methods he gave us to use does cast (TreeComparable) in it here which I am still not 100% sure why that is the line that the compiler freezes at and gives me the error
java.lang.ClassCastException: class ObjectTreeNode cannot be cast to class
TreeComparable (ObjectTreeNode and TreeComparable are in unnamed module of loader java.net.URLClassLoader
and this is the method that is causing it
public void insertBSTDup(Object o) {
ObjectTreeNode p, q;
ObjectTreeNode r = new ObjectTreeNode(o);
if (root == null)
root = r;
else {
p = root;
q = root;
while (q != null && ((TreeComparable)(r.getInfo())).compareTo(p.getInfo()) != 0) { <---------
p = q;
if (((TreeComparable)(r.getInfo())).compareTo(p.getInfo()) < 0)
q = p.getLeft();
else
q = p.getRight();
}
if (((TreeComparable)(r.getInfo())).compareTo(p.getInfo()) < 0)
setLeftChild(p, r);
else if (((TreeComparable)(r.getInfo())).compareTo(p.getInfo()) > 0)
setRightChild(p, r);
else ((TreeComparable)(p.getInfo())).operate(r.getInfo());
}
}
My Word class is this so far, and the compareTo method is at the bottom, which is implemented in a similar way to the first compareTo I did on my first assignment, and it is comparing word strings so it knows where it will be added.
public class Word implements TreeComparable
{
private String word;
private ObjectList list = new ObjectList();
private ObjectListNode obj;
private int numberOfTimes = 1, LineNumber, position;
public Word(String word, int LineNumber, int position)
{
this.word = word;
this.LineNumber = LineNumber;
this.position = position;
}
public int compareTo(Object o)
{
Word w = (Word) o;
return word.compareTo(w.getWord());
}
public String getWord()
{
return word;
}
and this is the treeComparable method
public interface TreeComparable
{
public int compareTo(Object O);
public void operate(Object O);
public void visit();
}
what can I change to make it so that error to go away, other than remove the treeComparable casting, which I must keep going for this project
Also, this is the objectTreeNode object that the Word object will go into
public class ObjectTreeNode implements ObjectTreeNodeInterface
{
private Object info;
private ObjectTreeNode left;
private ObjectTreeNode right;
public ObjectTreeNode() {
info = null;
left = null;
right = null;
}
public ObjectTreeNode (Object o) {
info = o;
left = null;
right = null;
}
public void setInfo(Object o) {
info = o;
}
public Object getInfo() {
return info;
}
public void setLeft(ObjectTreeNode p) {
left = p;
}
public ObjectTreeNode getLeft() {
return left;
}
public void setRight(ObjectTreeNode p) {
right = p;
}
public ObjectTreeNode getRight() {
return right;
}
}
And here is main
public static void main(String args[]) throws IOException
{
Hash h = new Hash();
Word w;
ObjectBinaryTree bt = new ObjectBinaryTree();
ObjectTreeNode node;
Scanner in = new Scanner(new File("getty.txt"));
PrintWriter pw = new PrintWriter(new FileWriter("csis.txt"));
int numberOfLines = 1;
//h.check();
while(in.hasNext())
{
String word = in.nextLine();
String[] ar = word.split(" ", 0);
System.out.print("\n" + (numberOfLines++) + ": ");
int i = 0;
while(i < ar.length)
{
char check = ar[i].charAt(ar[i].length() - 1);
if(check == ',' || check == '.' || check == '!' || check == '?')
{
ar[i] = ar[i].substring(0, ar[i].length() - 1);
}
w = new Word(ar[i], numberOfLines, (i + 1));
node = new ObjectTreeNode(w);
//System.out.println(ar[i]);
bt.insertBSTDup(node);
System.out.print("(" + (i + 1) + ") " + ar[i] + " ");
i++;
}
}
}
Your insertBSTDup method expects every return value of getInfo to be of type TreeCompareable. It also accepts as input parameter an object which is presumably the object to insert, which therefore should also be a TreeCompareable. In fact you wrap it in an ObjectTreeNode right away:
public void insertBSTDup(Object o) {
ObjectTreeNode p, q;
ObjectTreeNode r = new ObjectTreeNode(o);
However, when you call insertBSTDup you don't pass in a Word object (which would implement TreeComparable but a ObjectTreeNode instead:
node = new ObjectTreeNode(w);
bt.insertBSTDup(node);
So either change the parameter of insertBSTDup to a ObjectTreeNode and get rid of wrapping it again or pass w into insertBSTDup instead of Node.
In a more general sense, much of this could have been avoided if you didn't just take a Object as the parameter, when you really expect a TreeComparable. That way the compiler would have told you that an ObjectTreeNode is not a TreeComparable instead of the problem only occurring at runtime.
Basically every place where you use Object should be TreeComparable instead. And in fact you should probably use a generic type instead, if you already learned of them.

Evaluate a Postfix Expression Using a Singly Linked List

I'm writing a program that asks the user for a postfix expression, and then outputs the result to the expression. I am attempting to do this using a Singly Linked List, and using the Adapter Pattern to create a stack.
The code for the SinglyLinkedList class, the LinkedStack class, and the Stack implementation are all straight out of a Data Structures book that I own. So the SinglyLinkedListTest class is the only one that has my own code in it (and has errors).
I've written a program that simply uses a stack to evaluate a postfix expression before, but I'm getting confused this time with the extra classes included.
I'm sure I have a ton of errors, but the most obvious ones to me are in my SinglyLinkedListTest class, every time I push a value onto the stack. I know the issue is that I am attempting to push Objects and characters onto the stack instead of the arguments that match push(E e), but I don't know how to alter my code to make this work.
Any suggestions or input would be greatly appreciated.
Here is my Stack Implementation:
package PostFix;
public interface Stack<E>
{
int size();
boolean isEmpty();
void push(E e);
E pop();
}
Here is my LinkedStack class:
package PostFix;
public class LinkedStack <E> implements Stack<E>
{
private SinglyLinkedList<E> list = new SinglyLinkedList<>();
public LinkedStack()
{
}
public int size()
{
return list.size();
}
public boolean isEmpty()
{
return list.isEmpty();
}
public void push(E e)
{
list.addFirst(e);
}
public E pop()
{
return list.removeFirst();
}
}
Here is my SinglyLinkedList class:
package PostFix;
public class SinglyLinkedList<E>
{
private static class Node<E>
{
private E element;
private Node<E> next;
public Node(E e, Node<E> n)
{
element = e;
next = n;
}
public E getElement()
{
return element;
}
public Node<E> getNext()
{
return next;
}
}
private Node<E> head = null;
private Node<E> tail = null;
private int size = 0;
public SinglyLinkedList()
{
}
public int size()
{
return size;
}
public boolean isEmpty()
{
return size == 0;
}
public void addFirst(E e)
{
head = new Node<>(e, head);
if (size == 0)
{
tail = head;
}
size++;
}
public E removeFirst()
{
if (isEmpty())
{
return null;
}
E answer = head.getElement();
head = head.getNext();
size--;
if (size == 0)
{
tail = null;
}
return answer;
}
}
Here is my final SinglyLinkedListTest class:
package PostFix;
import java.util.Scanner;
public class SinglyLinkedListTest
{
public static void main(String[] args)
{
Double num1, num2, answer;
char c;
Stack<Double> stack = new LinkedStack<>();
Scanner input = new Scanner(System.in);
System.out.println("Enter the expression you would like to evaluate: ");
String someString = input.nextLine();
for (int index = 0; index < someString.length(); index++)
{
c = someString.charAt(index);
if (Character.isDigit(c))
{
stack.push((double)Character.digit(c, 10));
}
else if (c == '+')
{
num2 = stack.pop();
num1 = stack.pop();
answer = num1+num2;
stack.push(answer);
}
else if (c == '-')
{
num2 = stack.pop();
num1 = stack.pop();
answer = num1-num2;
stack.push(answer);
}
else if (c == '*')
{
num2 = stack.pop();
num1 = stack.pop();
answer = num1*num2;
stack.push(answer);
}
else if (c == '/')
{
num2 = stack.pop();
num1 = stack.pop();
answer = num1/num2;
stack.push(answer);
}
}
System.out.println("The result is: " + stack.pop());
}
}
Stack<String> buffer = new LinkedStack<>();
Poor name: call it stack.
You've declared it as Stack<String> but you're pushing chars:
buffer.push(someString.charAt(index));
and Objects:
buffer.push(answer);
and popping ints:
num1 = buffer.pop();
You are never either pushing or popping strings.
Just make up your mind. You should be pushing and popping ints, or longs, or doubles, or BigDecimals, depending on what precision you need.
EDIT
buffer.push((double)c);
is invalid. You're pushing the ASCII value, not the numeric value it corresponds to. You need
buffer.push((double)Character.digit(c, 10));
You also need an else after each if block: if the character is a digit, it won't be a +, and if it's a + it won't be a -, etc.

Get Words out of a Trie Data Structure

i have the following Trie Data Structure:
public class CDictionary implements IDictionary {
private static final int N = 'z' -'a'+1;
private static class Node {
private boolean end = false;
private Node[] next = new Node[N];
}
private int size = 0;
private Node root = new Node();
#Override
public boolean contains(String word) {
Node node = this.contains(root,word,0);
if (node == null) {
return false;
}
return node.end;
}
private Node contains(Node node, String str, int d) {
if (node == null) return null;
if (d == str.length()) return node;
char c = str.charAt(d);
return contains(node.next[c-'a'], str, d+1);
}
#Override
public void insert(String word) {
this.root = insert(this.root, word, 0);
this.size++;
}
private Node insert(Node node, String str, int d) {
if (node == null) node = new Node();
if (d == str.length()) {
node.end = true;
return node;
}
char c = str.charAt(d);
node.next[c-'a'] = this.insert(node.next[c-'a'], str, d+1);
return node;
}
#Override
public int size() {
return size;
}
The Trie is filled with some words like
for, the, each, home, is, it, egg, red...
Now i need a function to get all Words with a specific length for example the length 3
public List<String> getWords(int lenght) {
}
With the Words mentioned above it should return a list with the words
for,the,egg,red
The Problem is how can i restore these words out of the Trie Structur?
You need to recurse through your structure to a maximum depth of N (in this case 3)
You could do this by adding a couple of methods to your dictionary...
public List<String> findWordsOfLength(int length) {
// Create new empty list for results
List<String> results = new ArrayList<>();
// Start at the root node (level 0)...
findWordsOfLength(root, "", 0, length, results);
// Return the results
return results;
}
public void findWordsOfLength(Node node, String wordSoFar, int depth, int maxDepth, List<String> results) {
// Go through each "child" of this node
for(int k = 0; k < node.next.length; k++) {
Node child = node.next[k];
// If this child exists...
if(child != null) {
// Work out the letter that this child represents
char letter = 'a' + k;
// If we have reached "maxDepth" letters...
if(depth == maxDepth) {
// Add this letter to the end of the word so far and then add the word to the results list
results.add(wordSoFar + letter);
} else {
// Otherwise recurse to the next level
findWordsOfLength(child, wordSoDar + letter, depth + 1, maxDepth, results);
}
}
}
}
(I have not compiled / tested this, but it should give you an idea of what you need to do)
Hope this helps.

NullPointerException when deleting a trie word

Below is the code. The array index represents the small characters(a-z) and index is 26 (number of characters in english alphabets). It is a dictionary of words in which the children[character ascii value-97] points to the next node. The end of word is given bool terminal=true.
All functions are recursive. In delete function, we have to traverse to the end of the word character by character. While traversing, on the second call of recursive delete, I lose all my references and NullPointerException occurs.
The line of code which is making trouble has a comment in front of it. First there is a check if word exist in dictionary or not.
import java.io.File;
import java.util.Scanner;
public class xxx {
public static void main(String[] args) {
Trie trie = new Trie();
if (trie.delete(word)) {
System.out.println("Word deleted");
} else {
System.out.println("Word not present");
}
break;
}
case "S": { //Search for the word
String word = tokens[1];
if (trie.isPresent(word)) {
System.out.println("Word found");
} else {
System.out.println("Word not found");
}
}
This class just calls the recursive functions of the Node class. The trie class gets call from the main class and then shifts the data to recursive functions in Node class
class Trie {
Node root;
public Trie() {
root = new Node();
}
boolean isPresent(String s) { // returns true if s is present, false otherwise
current = root;
for (int i = 0; i < s.length(); i++) {
if (current.children[(int) s.charAt(i) - 97] == null) {
return false;
} else {
current = current.children[(int) s.charAt(i) - 97];
}
}
if (current.terminal == false) {
return false;
}
return true;
}
boolean delete(String s) { // returns false if s is not present, true otherwise
if (!isPresent(s)) {
return false;
}
root.delete(root,s);
return true;
}
int membership() { // returns the number of words in the data structure
return root.membership(root, 0);
}
void listAll() { // list all members of the Trie in alphabetical orber
root.listAll(root, "");
}
}
The children[ascii value-97] will reference a node and this link will represent alphabetic character. The outDegree will make sure that only the given string is deleted. This class has all recursive functions.
class Node {
boolean terminal;
int outDegree;
Node[] children;
public Node() {
terminal = false;
outDegree = 0;
children = new Node[26];
}
public void delete(Node x, String s) {
if (s.length() > 1){
if(i<s.length())
delete(children[s.charAt(0)-97],s.substring(1)); //this is where problem occurs
}
else if(children[((int)s.charAt(0))-97].outDegree>0)
terminal =false;
else if(children[((int)s.charAt(0))-97].outDegree==0){
children[((int)s.charAt(0))-97]=null;
return;
}
if(children[s.charAt(0)-97].outDegree==0)
children[s.charAt(0)-97]=null;
}
}
Your problem is not in the line of code you commented. Your problem is how you initialized the array:
children = new Node[26];
This line of code allocates memory of the array. However, the value of each individual element of the array is set to NULL for object references, unicode NULL character for char primitives, false for boolean primitives, and to 0 for number primitives. If you want this to work, you must initialize the array properly.

Tree printing extra characters

public class TreeWords {
public static void main (String[] args){
Tree tree = new Tree();
System.out.println("Enter your string.");
Scanner in = new Scanner(System.in);
String input = in.next();
for (char ch : input.toCharArray()) {
Tree tmp = new Tree(ch);
tree.insert(tree, tmp);
}
tree.printInOrder(tree);
}
}
class Tree {
//Tree variables
char letter;
Tree left, right;
//Constructors
public Tree(){
left = right = null;
}
public Tree(char input) {
left = right = null;
letter = input;
}
//Methods
public void printInOrder(Tree root) {
if (root == null) return;
printInOrder(root.left);
System.out.print(root.letter);
printInOrder(root.right);
}
public void insert(Tree root, Tree tmp) {
if (root == null) {
root = tmp;
return;
}
if (root.left == null) {
root.left = tmp;
return;
}
if (root.right == null) {
root.right = tmp;
return;
}
insert(root.left, tmp);
insert(root.right, tmp);
}
}
This is my sample code for a small program that I'm working on. Basically, it is supposed to add a character to each tree node. But somehow, there seems to be either printing extra characters, or adding extra characters.
For example:
Input : aaa
Output : aaaa
Input : hello
Output : oloholo�oloeolo
There's a couple of problems here. These two will hopefully get you started
The first is that parameters in Java are pass-by-value, so assigning a value to them will not be visible outside the method. So the first four lines of 'insert' do nothing.
The second is that once a node is 'full' (i.e. both left and right are non-null) you are inserting the next value into both the left and right sub-trees.
It's also possible that you're missing a '<' comparison in the insert method too, but I'm not sure if 'printInOrder' is referring to insert order or lexicographic order.

Categories