Wrong Implementation of Binary Search Tree's search Function - java

I have a Binary Search Tree and I think one of my method is working incorrectly. The program I have is a program that separates the strings read from a file word by word and deletes the special characters in it, then transfers these words to the data structure in alphabetical order. If the same word was previously conveyed during the transmission, it increases the frequency of that word. While checking the output of my program, I saw something like this.
MY OUTPUT:
Readed Line: sun-meal //After some operation it is seperated like "sun" and "metal"
String inserted.
String inserted.
Readed Line: sun-oil //After some operation it is seperated like "sun" and "oil"
String inserted.
String inserted. //Error is here.
TRUE OUTPUT SHOULD BE:
Readed Line: sun-meal //After some operation it is seperated like "sun" and "metal"
String inserted.
String inserted.
Readed Line: sun-oil //After some operation it is seperated like "sun" and "oil"
String inserted.
Repeated String. Frequency +1. //It should be like that.
I will share my source code but what I want to know is what am I doing wrong? Why is "sun" inserted 2 times?
TreeDriver Class:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class TreeDriver
{
public static void main(String [] args) throws FileNotFoundException {
Tree stTree = new Tree();
TreeNode compareNode;
Scanner scan = new Scanner(new File(args[0]));
while (scan.hasNextLine()) {
String data = scan.nextLine();
System.out.println("Readed Line: "+data);
String[] convertedData = data.replaceAll("[^a-zA-Z ]", " ").toLowerCase().split("\\s+");
int y = 0;
try {
while(convertedData[y] != null){
String st = convertedData[y];
if (st.contains(" ")) {
}
else{
compareNode = Tree.search(stTree.getRoot(), st);
if (compareNode != null) {
compareNode.upFreq();
System.out.println("\tRepeated String. Frequency +1.");
} else {
stTree.insert(st);
System.out.println("\tString inserted.");
}
y++;
}
}
}
catch(Exception ignored) {
}
}
scan.close();
}
}
TreeNode Class
public class TreeNode
{
private int freq; //frequency of the String in the Node
private String stValue;
private TreeNode left;
private TreeNode right;
public TreeNode(String st)
{
stValue = st;
left = null;
right = null;
freq = 1;
}
public void add(String st)
{
if (left == null)
{
left = new TreeNode(st);
}
else if (right == null)
{
right = new TreeNode(st);
}
else
{
if(countNodes(left) <= countNodes(right))
{
left.add(st);
}
else
{
right.add(st);
}
}
}
//Count the nodes in the binary tree to which root points, and
public static int countNodes( TreeNode root ) {
if ( root == null )
// The tree is empty. It contains no nodes.
return 0;
else {
// Start by counting the root.
int count = 1;
// Add the number of nodes in the left subtree.
count += countNodes(root.getLeft());
// Add the number of nodes in the right subtree.
count += countNodes(root.getRight());
return count; // Return the total.
}
}
public TreeNode getLeft(){
return left;
}
public TreeNode getRight(){
return right;
}
public String getString()
{
return stValue;
}
public void upFreq()
{
freq = freq + 1;
}
public int getFreq()
{
return freq;
}
}
Tree Class:
public class Tree
{
private TreeNode root;
public Tree()
{
root = null;
}
public boolean isEmpty()
{
return root == null;
}
public void insert(String st)
{
if (isEmpty())
{
root = new TreeNode(st);
}
else
{
root.add(st);
}
}
public TreeNode getRoot()
{
return root;
}
public static TreeNode search(TreeNode root, String st)
{
if(root == null)
{
return null;
}
else if(st.equals(root.getString()))
{
return root;
}
else
{ if (root.getLeft() != null)
return search(root.getLeft(), st);
else
return search(root.getRight(), st);
}
}
public TreeNode found(TreeNode root)
{
return root;
}
public static void preorderPrint(TreeNode root)
{
if ( root != null )
{
System.out.print( root.getString() + " " ); // Print the root item.
preorderPrint( root.getLeft() ); // Print items in left subtree.
preorderPrint( root.getRight() ); // Print items in right subtree.
}
}
}
Can you please help me find the problem?

Indeed, your search function is wrong :
if (root.getLeft() != null)
return search(root.getLeft(), st);
else
return search(root.getRight(), st);
You are going through the right child node only if the left one is null, when you should go through both.

Related

finding most frequent element in BST

i have a BST and each node contain a word and a frequencies.
the BST sorted according to the word.
before inserting into the BST we must check if the word in BST or not, if it is not insert it.
if it is there i will increase the frequencies by 1.
the question is
how to get the word which have the highest frequencies?
here is my BST class
public class BST {
private BSTword root;//root as reference variable
// CONSTRUCTORS
public BST() {
root = null;
}
and this is the node which contain the word and its frequencies
public class BSTword {
private int freq;
private String word;
private BSTword left;
private BSTword right;
public BSTword() {
word = "";
left = right = null;
}
public BSTword(String word) {
this.word = word;
freq=1;
left = right = null;
}
and here is what i have done so far
this method in BST class
private BSTword mostCommonWord(BSTword p, int c) {
if (p == null) {//No Subtree
return p;
} else {
if (p != null) {
if (p.getData() == c) {
return p;
}
mostCommonWord(p.getLeft(), c);
if (p.getLeft().getData() > c) {
return p;
}
if (p.getRight().getData() > c) {
mostCommonWord(p.getRight(), c);
}
}
}
return p;
}

Tree traversing doesn't print desired solution

(java)
I have class called Node, which has following fields:
value (integer)
connectedNodes (array of Node objects, always has same size = 2)
combination (object of Combination class)
Combination class has one field called messageContext, let's just say that it's a message which needs to be shown on the screen when something happens (described later).
Also, we have one Tree object, which has only one field: root (Node object)
Now, let's say that we have one String called combinationStr = "1121". Now, we use Tree's method called addCombination:
public void addCombination(Combination finalCombination, Node current, String combination, int counter) {
if(counter==combination.length()) {
return;
}
int value = combination.charAt(counter)-48;
if(current.connectedNodes[value-1]==null) {
current.connectedNodes[value-1] = new Node(value);
}
if(counter==combination.length()-1) {
current.combination = finalCombination;
return;
}
addCombination(finalCombination,current.connectedNodes[value-1],combination,counter+1);
}
finalCombination object is an object that is going to be assigned to the last Node's combination field, added to the Tree for one combinationStr. So, we use this function to create the Tree-like structure that has path: -1 (root) -> 1 -> 1 -> 2 -> 1
When we come to the last one, traversing the Tree, we should see message appear. This is the messageContext of finalCombination.
Okay so, now let's use while(true) loop that will let us input a number, which will be like a path-chooser. If we input 1, we will go to node 1 and have other options to choose.
While loop looks like this:
Scanner scanner = new Scanner(System.in);
Node currentNode = tree.root;
while(true) {
for(Node node: currentNode.connectedNodes) {
if(node!=null) {
System.out.print(node.value + " ");
continue;
}
System.out.print("nullnode ");
}
System.out.println("");
if(currentNode.combination!=null) {
System.out.println(currentNode.combination.messageContext);
}
if(currentNode.connectedNodes[0]==null && currentNode.connectedNodes[1]==null) {
currentNode = tree.root;
System.out.println("root");
}
int x = scanner.nextInt();
currentNode = tree.takeStep(currentNode,x);
}
So, what are we doing here is actually printing the value of current Node, then printing values of Node's we can go to. If Node doesn't exist, we print nullnode.
The takeStep() method looks like this:
public Node takeStep(Node current, int value) {
if(current.connectedNodes[value-1]!=null) {
return current.connectedNodes[value-1];
}
return this.root;
}
It just checks if there is a node we want to go to and returns that node, if it does. If it doesn't exist, it will return us to root.
But, what's the problem with this code ?
Well, look at the whole main class:
Tree tree = new Tree(new Node(-1));
String[] combination = {"1121","11","2212"};
for(String s: combination) {
Combination tempCombination = new Combination();
tempCombination.messageContext = s + " ova poruka";
tree.addCombination(tempCombination,tree.root,s,0);
tree.traverse(tree.root);
System.out.println("END");
}
Scanner scanner = new Scanner(System.in);
Node currentNode = tree.root;
while(true) {
System.out.println(currentNode.value);
for(Node node: currentNode.connectedNodes) {
if(node!=null) {
System.out.print(node.value + " ");
}
else {
System.out.print("nullnode ");
}
}
int x = scanner.nextInt();
if(currentNode.combination!=null) {
System.out.println(currentNode.combination.messageContext);
if(currentNode.connectedNodes[0]==null && currentNode.connectedNodes[1]==null) {
currentNode = tree.root;
break;
}
}
currentNode = tree.takeStep(currentNode,x);
}
When we enter number x, we will call takeStep and check if that node exists connected to current one. But the problem is: When we input 1, it prints everything normally, when we input 1 again, it prints everything normally, when we input 2, it prints everything normally... but when we input 1 again, it says there are 2 nullnodes, and for some reason it doesn't change to root. Can anyone help me please? Here are the full classes:
NODE:
public class Node {
int value;
Node[] connectedNodes = {null,null};
Combination combination;
public Node(int value) {
this.value = value;
this.combination = null;
}
}
TREE:
public class Tree {
Node root;
public Tree(Node root) {
this.root = root;
}
public void addCombination(Combination finalCombination, Node current, String combination, int counter) {
if(counter==combination.length()) {
return;
}
int value = combination.charAt(counter)-48;
if(current.connectedNodes[value-1]==null) {
current.connectedNodes[value-1] = new Node(value);
}
if(counter==combination.length()-1) {
current.combination = finalCombination;
return;
}
addCombination(finalCombination,current.connectedNodes[value-1],combination,counter+1);
}
public void traverse(Node current) {
System.out.print(current.value+ " ");
for(Node node: current.connectedNodes) {
if(node!=null) {
traverse(node);
}
}
}
public Node takeStep(Node current, int value) {
if(current.connectedNodes[value-1]!=null) {
return current.connectedNodes[value-1];
}
return this.root;
}}
COMBINATION:
public class Combination {
String messageContext;
}
Can you please help me ? I just want to reset to root when it hasn't anywhere to go else ? Thank you in advance!
I ran your code and found out that you are storing the message context in the parent node instead of the actual node which marks the end of the combination. So I changed this piece of code in addCombination.
public void addCombination(Combination finalCombination, Node current, String combination, int counter) {
if (counter == combination.length()) {
//Storing at the original node.
current.combination = finalCombination;
return;
}
int value = combination.charAt(counter) - 48;
if (current.connectedNodes[value - 1] == null) {
current.connectedNodes[value - 1] = new Node(value);
}
addCombination(finalCombination, current.connectedNodes[value - 1], combination, counter + 1);
}
And changed following in the main code.
while (true) {
System.out.println(currentNode.value);
//Moved it up now as the node it self has the message context.
if (currentNode.combination != null) {
System.out.println(currentNode.combination.messageContext);
if (currentNode.connectedNodes[0] == null && currentNode.connectedNodes[1] == null) {
currentNode = tree.root;
continue;
}
}
for (Node node : currentNode.connectedNodes) {
if (node != null) {
System.out.print(node.value + " ");
} else {
System.out.print("nullnode ");
}
}
int x = scanner.nextInt();
currentNode = tree.takeStep(currentNode, x);
}
Now try the code it is resetting to root as expected.

Tree iterator in Java

I have implemented a code which adds elements in a tree and prints them in increasing order. However my aim is to learn iterators and want to replace the inOrder() function with an iterator function. How can I do this?
import java.util.InputMismatchException;
import java.util.Scanner;
import javax.xml.soap.Node;
class Tree
{
public final int mVal;
public Tree mLeft;
public Tree mRight;
public Node next;
public Tree(int val)
{
mVal = val;
}
public void add(int val)
{
if (val < mVal)
{
if (mLeft == null)
mLeft = new Tree(val);
else
mLeft.add(val);
}
else
{
if (val > mVal)
{
if (mRight == null)
mRight = new Tree(val);
else
mRight.add(val);
}
}
}
public String inOrder()
{
return ((mLeft == null) ? "" : mLeft.inOrder())
+ mVal + " "
+ ((mRight == null) ? "" : mRight.inOrder());
}
public static void main(String[] args)
{
Tree t = new Tree(8);
Scanner scanner = new Scanner(System.in);
boolean continueLoop = true; // determines if more input is needed
for (int i = 1; i < 9; ++i)
{
try // read two numbers and calculate quotient
{
System.out.print("Please enter a random integer : ");
int stackInt = scanner.nextInt();
t.add(Integer.valueOf(stackInt));
} // end try
catch (InputMismatchException inputMismatchException){
System.err.printf("\nException: %s\n", inputMismatchException);
scanner.nextLine(); //discard input so user can try again
System.out.println("You must enter integers. Please try again.\n");
} // end catch
}
System.out.println("Values in order = "+ t.inOrder());
}
}
look at this picture
First Step: if node has a left child, visit left child and do the first step with the child
Second Step: node has no left child (or we visited the left child already), add it to the inorder list
Third Step: first step with right child
i didnt test it
#Override
public String toString() {
return String.valueOf(mVal);
}
public String inOrder(Tree root) {
List<Tree> inOrder = new ArrayList<>();
inOrderRecursively(root, inOrder);
return inOrder.toString();
}
private void inOrderRecursively(Tree Node, List<Tree> inOrder) {
if (Node.mLeft != null) {
inOrderIt(Node.mLeft, inOrder);
}
inOrder.add(Node);
if (Node.mRight != null) {
inOrderIt(Node.mRight, inOrder);
}
}
greetings

Comparing tree structures of haystack and needle

I want to write a method that would record all positions of nodes of haystack starting from where the pattern (structure) of itself matches as that of the needle. The value stored in the node doesn't need to be equal, its just the pattern that is supposed to match.
Illustration
Example 1
If I have the following haystack and needle
In the example above, the program is expected to record
ROOT
ROOT->Left
Example 2
If I have the same haystack as that of above and my needle as
Then my program is expected to record,
ROOT
ROOT->Left
ROOT->Right
However, it seems like the way I am implementing my code is flawed because my method even records positions that shouldn't have been true.
The way I am implementing my code is, I have the following method that would return a list which contains all such positions and I am using a isSubtree method to check if the pattern starting from a particular node finds a match.
public static List<String> searchForNeedleInHaystack(Node haystack,
Node needle) {
List<String> resultList = new ArrayList<String>();
if(haystack.getLeftChild() != null) {
value = value + "L";//value is just a global string variable initially ""
if(isSubtree(haystack.getLeftChild(), needle)) {
resultList.add(value);
} else {
if(value.length() > 1)
value = value.substring(0, value.length() - 1);
}
searchForNeedleInHaystack(haystack.getLeftChild(), needle);
}
if(haystack.getRightChild() != null) {
value = value + "R";
if(isSubtree(haystack.getRightChild(), needle)) {
resultList.add(value);
} else {
if(value.length() > 1)
value = value.substring(0, value.length() - 1);
}
searchForNeedleInHaystack(haystack.getRightChild(), needle);
}
return resultList;
}
public static boolean isSubtree(Node haystack, Node needle) {
if(needle == null)
return true;
if(haystack == null)
return false;
return isSubtree(haystack.getLeftChild(), needle.getLeftChild()) && isSubtree(haystack.getRightChild(), needle.getRightChild());
}
Node class
public class Node {
private String info;
private Node leftChild = null;
private Node rightChild = null;
public Node() {
this("");
}
public Node(String info) {
this.info = info;
}
public void setinfo(String info) {
this.info = info;
}
public void setLeftChild(Node n) {
leftChild = n;
}
public void setRightChild(Node n) {
rightChild = n;
}
public Node getLeftChild() {
return leftChild;
}
public Node getRightChild() {
return rightChild;
}
public String getinfo() {
return info;
}
public boolean isLeaf() {
return rightChild == null && leftChild == null;
}
}
Problem
I just wanted to know what logic could I perhaps use so that I can compare for subtree structures successfully?
Thanks in advance!

In-order traversal of BST not working correctly?

So I'm writing a program to record words from a file in an array of binary trees. The array is of size 26, each index representing a letter of the alphabet. And each element is a BST with Nodes consisting of a word and queue of line numbers (still working on that, for now it just makes a new node instead of adding a new line number to the queue)
The problem I'm running into is with tree traversal. root.toString() never prints anything to the console, but it will always print "Empty". Not too sure why this is, so any insight would help a lot!
(Please keep in mind that some code in here was just for my testing purposes and some less important things are not yet implemented completely.)
BinarySearchTree.java
import java.util.LinkedList;
import java.util.Queue;
//Binary Search Tree (BST)
public class BinarySearchTree{
//Pointer to root Node
private Node root = null;
//Nested Node class
static class Node{
//Node contents
private String word;
private Node leftChild;
private Node rightChild;
private Queue<String> queue = new LinkedList<String>();
public Node(String word, String line){
this.word = word;
this.queue.add(line);
this.leftChild = null;
this.rightChild = null;
}//End constructor
public void setLeftChild(Node left){
this.leftChild = left;
}//End setLeftChild
public void setRightChild(Node right){
this.rightChild = right;
}//End setRightChild
public Node getLeftChild(){
return this.leftChild;
}//End getLEftChild
public Node getRightChild(){
return this.rightChild;
}//End getRightChild
public String getWord(){
return this.word;
}//End getWord
#Override
public String toString() {
//return this.getWord() + this.view(); //TODO fix later
return "This is the toString for a Node";
}//End toString
public String dequeue() {
return this.queue.remove();
}//End dequeue
public String view() {
return this.queue.peek();
}//End view
}//End Node class
public Node getRoot() {
return this.root;
}//End getRoot
public void setRoot(Node n) {
this.root = n;
}//End setRoot
// insert a node to the binary search tree
public void insert(Node root, Node newNode){
//If no root (empty tree), newNode is root
if(root == null) {
setRoot(newNode);
}
//If root word > newNode word, move left
else if(root.getWord().compareToIgnoreCase(newNode.getWord()) > 0){
//No left child, insert here
if(root.getLeftChild() == null){
root.setLeftChild(newNode);
}
//Left child exists, recurse
else{
insert(root.getLeftChild(),newNode);
}
}
//If root word < newNode word, move right
else if(root.getWord().compareToIgnoreCase(newNode.getWord()) < 0){
//No right child, insert here
if(root.getRightChild() == null){
root.setRightChild(newNode);
}
//Right child exists, recurse
else{
insert(root.getRightChild(),newNode);
}
}
}//End insert
//in-order Traversal of Node
public void inOrderTraversal(Node root){
if(root != null){
inOrderTraversal(root.getLeftChild());
root.toString();
inOrderTraversal(root.getRightChild());
}
else
System.out.println("Empty");
}//End inOrderTraversal
}
FileSorter.java
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class FileSorter {
//Create BST Array
private static BinarySearchTree[] bstArray = new BinarySearchTree[26];
public static void main(String[] args) throws FileNotFoundException {
//Initialize the 26 BSTs
for(int i = 0; i < 26; i++) {
bstArray[i] = new BinarySearchTree();
}
//File to work with
File file = new File("Gettysburg.txt");
//Sort through file
scanByLine(file);
bstArray[1].inOrderTraversal(bstArray[1].getRoot());
System.out.println("Complete!");
}//End main
/*
* Below are methods for scanning a file, and also cleaning/stripping it
* of all non alphabetic characters so they will more cleanly fit in a Node
*/
public static void scanByLine(File f) throws FileNotFoundException {
//Keep track of line number
int lineNum = 1;
Scanner line = new Scanner(f);
//While there is another line, scan it, pass to scanWords, increment lineNum
while(line.hasNextLine()) {
String alphaString = removeNonAlpha(line.nextLine());
scanWords(alphaString, lineNum);
if(!alphaString.isEmpty()) {
lineNum++;
}
}
//Close line scanner when finished
line.close();
}//End scanByLine
public static void scanWords(String s, int line) {
Scanner word = new Scanner(s);
//While another word exists, scan it, place new node into array
while(word.hasNext()) {
String nodeWord = word.next().toLowerCase();
String nodeLine = Integer.toString(line);
//Add newWord to appropriate index of bstArray
int index = (int)nodeWord.charAt(0) - 97;
System.out.println("Creating Node.");
//Create new Node
BinarySearchTree.Node newNode = new BinarySearchTree.Node(nodeWord, nodeLine);
System.out.println("Created. Adding Node with " + newNode.getWord() + " at line: " + newNode.view());
bstArray[index].insert(bstArray[index].getRoot(), newNode);
}
//Close word scanner when finished
word.close();
}//End scanWords
//Remove anything non a-z and A-Z
public static String removeNonAlpha(String s) {
s = s.replaceAll("[^A-Za-z]", " ");
return s;
}
}
The problem is that you call root.toString() but you don't do anything with the return value. And at the end when there are no more leaves you will just print Empty.
You should change
root.toString();
to
System.out.println(root.toString()):

Categories

Resources