I am doing my assignment and my last question asks me to write a program that uses binary search tree of characters. You will read in a sequence of characters from input,
representing a preorder traversal of a binary search tree. You need to restore the original shape of the binary search tree from
this sequence and print the out the tree's content both in sideways (as illustrated below) and in an inorder fashion.
Ipublic class PrintSideways {
public static void main(String[] args) {
if(args.length == 0 || args[0].length() == 0)
{
throw new IllegalArgumentException ("This is an invalid argument");
}
String chars = args[0];
BinarySearchTree<StringItem, String> bst = new BinarySearchTree<StringItem, String>();
This is the skeleton code I received and I added the exception line to it. I am not really sure on how to start this code because I am weak on binarysearchtrees. Specifically, I don't get how to use the StringItem method in the parameter. This is the StringItem method provided.
public class StringItem extends KeyedItem<String> {
public StringItem(String str) {
super(str);
}
public String toString(){
return getKey()+"";
}
} // end StringItem
Some detailed explanation would be much appreciated :) Thank you.
Here is a quick implementation in C# but you would still need to tweak it to meet the needs of your structures. You should still get the idea of the algorithm or if you have trouble I can try to explain:
private BinaryTreeNode<int> ReconstructPreorderRecursive(List<int> inorder, List<int> preorder, int inorderStart, int inorderEnd)
{
BinaryTreeNode<int> root = new BinaryTreeNode<int>();
root.Value = preorder[preorderIndex];
int index = inorder.IndexOf(preorder[preorderIndex]);
//left subtree
if (index > inorderStart)
{
preorderIndex++;
root.LeftChild = ReconstructPreorderRecursive(inorder, preorder, inorderStart, index - 1);
if (root.LeftChild != null)
root.LeftChild.Parent = root;
}
//right subtree
if (index < inorderEnd)
{
preorderIndex++;
root.RightChild = ReconstructPreorderRecursive(inorder, preorder, index + 1, inorderEnd);
if (root.RightChild != null)
root.RightChild.Parent = root;
}
return root;
}
Usage:
newTree.Root = ReconstructPreorderRecursive(lstInorder, lstPreorder, 0, lstInorder.Count - 1);
Related
In my program, I have initialized a binary tree and I want to search if a node exists in that binary tree. If it does exist, then I will print the subtree of that node and the level it was found. I am able to perform my search method but I am not sure how to print the subtree of that node found and its level.
For example, this is my binary tree [K=3 L=[K=1 R=[K=2]] R=[K=5 L=[K=4]]. If I search for node 1, then it will return the node (not null) since it exists in my binary tree.
Problem: I need to print only the subtree of the node and the level where it was found: [K=1 R=[K=2]], level=1.
Here is my source code for reference:
Main Class
// instantiate BST object
BST<Character> bst = new BST<>();
// insert values to bst1
String str = "31254";
char[] letter = str.toCharArray();
for (int i = 0; i < letter.length; i++) {
Character c = letter[i];
bst1.insert(c);
}
// print bst
System.out.println("\nht=" + bst1.height + " " + bst1.toString() + "\n");
// search values in bst1
String str2 = "016483";
char[] letter2 = str2.toCharArray();
for (int i = 0; i < letter2.length; i++) {
Character c = letter2[i];
if (bst1.search(c) != null) { // if found, print the node (w/ subtree) and its level
// ** part that should print the subtree and its level
}
else {
System.out.println(c + " is not found.");
}
}
BST Class - where my search method is declared
public class BST<T extends Comparable<T>> extends BT<T> {
// insert() method
// search method
public BTNode<T> search(T k) {// my method
BTNode<T> n = root;
while (n != null) {
if (n.info.compareTo(k) == 0) {
return n;
}
else {
if (n.info.compareTo(k) > 0) {
n = n.left;
}
else {
n = n.right;
}
}
}
return null;
}
}
Thanks in advance!
I did not modify your code. Instead, I used an imaginary class Node that I've written. Also, I have written all of them as half pseudo half java code.
Suppose your node has only one int type variable and two children.
class Node{
int data;
Node left;
Node right;
}
You have a printExistingSubTree method in your BST class that does the what you exactly ask for:
printExistingSubTree(Node node, int key):
if (find(node.left, key, 0) != -1)
then
printTree(node.left)
print(find(node.left, key, 0))
if (find(node.right, key, 0) != -1)
then printTree(node.right)
printTree(node.right)
print(find(node.right, key, 0))
You have a find method in your BST class that does find the index:
int find(Node node,int key, int level)
if(node.data is equal to the key)
then return level
int left = -1;
if(node.leftChild is not null)
then left = find(node.left, key, level+1)
if(left != -1)
return left
int right = -1;
if(node.rightChild is not null)
then right = find(node.right, key, level+1)
return right
Then, to print, you should decide how you want to traverse the subtree.
You have a printTree method in your BST class that prints the subtree in postorder:
void printTree(Node node){
if (node == null)
return;
printTree(node.left);
printTree(node.right);
print(node.data + " ");
}
Note: I did not understand your whole code. Therefore, I have just written the answer of your question in the pseudo code format. I think, you can write your own code from that.
Note2: There may be some typos&wrong namings. PLease do not lynch. Just write in the comments and I'll correct.
I am struggling to figure out how to code a recursive algorithm to count the number of leaves in a Binary Tree (not a complete tree). I get as far as traversing to the far most left leaf and don't know what to return from there. I am trying to get the count by loading the leaves into a list and getting the size of that list. This is probably a bad way to go about the count.
public int countLeaves ( ) {
List< Node<E> > leafList = new ArrayList< Node<E> >();
//BinaryTree<Node<E>> treeList = new BinaryTree(root);
if(root.left != null)
{
root = root.left;
countLeaves();
}
if(root.right != null)
{
root = root.right;
countLeaves();
}
if(root.left == null && root.right == null)
{
leafList.add(root);
}
return();
}
Elaborating on #dasblinkenlight idea. You want to recursively call a countleaves on root node & pass back the # to caller. Something on the following lines.
public int countLeaves() {
return countLeaves(root);
}
/**
* Recursively count all nodes
*/
private static int countLeaves (Node<E> node) {
if(node==null)
return 0;
if(node.left ==null && node.right == null)
return 1;
else {
return countLeaves(node.left) + countLeaves(node.right);
}
}
Edit: It appears, a similar problem was previously asked counting number of leaf nodes in binary tree
The problem with your implementation is that it does not restore the value of member variable root back to the state that it had prior to entering the method. You could do it by storing the value in a local variable, i.e.
Node<E> oldRoot = root;
... // your method goes here
root = oldRoot;
However, a better approach is to take Node<E> as an argument, rather than relying on a shared variable:
public int countLeaves() {
return countLeaves(root);
}
private static int countLeaves (Node<E> node) {
... // Do counting here
}
I'm in the process of designing a program that is meant to search through a two-dimensional array of numbers that represents a map for a path to a specified end point. I've been using nodes that have several parameters, most prominently adjacent north, south, east, and west nodes each representing a square within the map. The search method I'm currently trying to finish is with iterative deepening but every time I try running the program, I wind up with a stack overflow error. This is the iterative deepening class.
import java.util.*;
import java.io.*;
public class IDeepeningSearch {
private Node start;
private Node end;
private int[][] map;
private ArrayList<Node> solution;
//Build using file handler
public IDeepeningSearch(String file){
FileHandler handle = new FileHandler(file);
//Create map
map = handle.getMap();
//Start node coordinates and value
start = new Node();
start.setRow(handle.getSRow());
start.setCol(handle.getSCol());
start.setValue(map[start.getRow()][start.getCol()]);
//End node coordinates
end = new Node();
end.setRow(handle.getERow());
end.setCol(handle.getECol());
end.setValue(map[start.getRow()][start.getCol()]);
}
//Runs search
public void run(){
int i = 0;
solution = new ArrayList<Node>();
//Value of i indicates depth to be explored; will increment with each failure
while(solution.isEmpty()){
search(start, i);
i++;
}
if(!solution.isEmpty()){
System.out.println("It worked.");
}
System.out.println("If you're not seeing the other message then it failed.");
}
//Building tree
public void build(Node head){
setNLeaf(head);
setSLeaf(head);
setELeaf(head);
setWLeaf(head);
// if(head.getNorth() != null){
// build(head.getNorth());
// }
// if(head.getSouth() != null){
// build(head.getSouth());
// }
// if(head.getEast() != null){
// build(head.getEast());
// }
// if(head.getWest() != null){
// build(head.getWest());
// }
}
//Performs search
public void search(Node head, int depth){
if(head.getRow() == end.getRow() && head.getCol() == end.getCol()){
solution.add(head);
return;
}
else{
if(depth == 0){
return;
}
build(head);
if(head.getNorth() != null){
search(head.getNorth(), depth--);
}
if(head.getSouth() != null){
search(head.getSouth(), depth--);
}
if(head.getEast() != null){
search(head.getEast(), depth--);
}
if(head.getWest() != null){
search(head.getWest(), depth--);
}
}
}
//Sets north leaf
public void setNLeaf(Node node){
//Determines if parent is on edge of map and if desired space has 0 value
if(node.getRow() != 0 && map[node.getRow() - 1][node.getCol()] != 0){
Node n = new Node();
n.setRow(node.getRow() - 1);
n.setCol(node.getCol());
n.setValue(map[n.getRow()][n.getCol()]);
n.setParent(node);
node.setNorth(n);
}
}
//Sets south leaf
public void setSLeaf(Node node){
//Determines if parent is on edge of map and if desired space has 0 value
if(node.getRow() != (map.length - 1) && map[node.getRow() + 1][node.getCol()] != 0){
Node n = new Node();
n.setRow(node.getRow() + 1);
n.setCol(node.getCol());
n.setValue(map[n.getRow()][n.getCol()]);
n.setParent(node);
node.setSouth(n);
}
}
//Sets east leaf
public void setELeaf(Node node){
//Determines if parent is on edge of map and if desired space has 0 value
if(node.getRow() != (map[0].length - 1) && map[node.getRow()][node.getCol() + 1] != 0){
Node n = new Node();
n.setRow(node.getRow());
n.setCol(node.getCol() + 1);
n.setValue(map[n.getRow()][n.getCol()]);
n.setParent(node);
node.setEast(n);
}
}
//Sets west leaf
public void setWLeaf(Node node){
//Determines if parent is on edge of map and if desired space has 0 value
if(node.getCol() != 0 && map[node.getRow()][node.getCol() - 1] != 0){
Node n = new Node();
n.setRow(node.getRow());
n.setCol(node.getCol() - 1);
n.setValue(map[n.getRow()][n.getCol()]);
n.setParent(node);
node.setWest(n);
}
}
}
I thought I was doing this correctly but the errors I've been getting have been pretty constant. This is what I wind up with.
Exception in thread "main" java.lang.StackOverflowError
at Node.setSouth(Node.java:88)
at IDeepeningSearch.setSLeaf(IDeepeningSearch.java:113)
at IDeepeningSearch.build(IDeepeningSearch.java:48)
at IDeepeningSearch.search(IDeepeningSearch.java:75)
at IDeepeningSearch.search(IDeepeningSearch.java:77)
at IDeepeningSearch.search(IDeepeningSearch.java:80)
at IDeepeningSearch.search(IDeepeningSearch.java:77)
The second-to-last and last lines repeat. I've tried building a full tree as well but that either gives me another stack overflow error or a null pointer exception. I'm not really sure what the issue is here but if I can fix this, I'm sure I can finish my breadth-first search method as well.
depth-- evaluates to the original value of depth. This means that the unmodified version of depth is being passed to the recursive call to search(), so your code is never approaching the base case. Try depth-1 instead. Or, if you need the value of the local variable depth to change, --depth.
For example, this will continually print 10 until it reaches stack overflow
public void foo(int x) {
if (x == 0) {
return;
}
System.out.println(x);
foo(x--);
}
foo(10);
The StackOverflowError is because of the flawed recursive calls of search(node, depth--) as Chris Rise has mentioned in his answer. Try --depth to fix this.
There is also poor memory management in this code, which is wasting heap memory that could either slow the program due to several calls to GC (Garbage-Collector) or lead to an OutOfMemeoryError! This problem is visible in the setXLeaf(Node n) methods (e.g. setNLeaf(Node north) etc.) where every time you are creating a new Node, while this can be done only when it's necessary with a simple check:
if (node.getSouth() == null) {
Node n = new Node();
n.setParent(node);
node.setSouth(n);
}
node.getSouth().setRow(node.getRow() + 1);
node.getSouth().setCol(node.getCol());
node.getSouth().setValue(map[node.getRow() + 1][node.getCol()]);
This way you will avoid creating new objects that are unnecessary. This should be fixed in all the setXLeaf(...) methods.
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.
In a school assignment I'm supposed to complete a method that should return an array of
node elements in ascendig order. The nodes are assembled in a binary search tree, so to sort them correct, I got a tip to create a recursive method to do the job.
The problem is that this doesn't even yield all the elements in the collection according to the test output (java.lang.AssertionError: toArray() does not return all the elements in the collection.)
I couldn't come up with any other way to deal with the array, and I'm not quite sure if the recursion even works. Any help is much appreciated.
Below is my code:
public class BinarySearchTree<E extends Comparable<E>> implements
IfiCollection<E> {
Node root;
Node current;
int size = 0;
int i = 0;
public class Node {
E obj;
Node left, right;
public Node(E e) {
obj = e;
}
} // END class Node
[...]
public E[] toArray(E[] a) {
Node n = root;
a = sort(n, a);
return a;
}
public E[] sort(Node n, E[] a) { //, int idx, E[] a) {
if (n.left != null) {
current = n.left;
sort(current, a);
}
a[i] = current.obj;
i++;
if (n.right != null) {
current = n.right;
sort(current, a);
}
return a;
} // END public Node sort
[...]
} // END class BinarySearchTree
Test output:
java.lang.AssertionError: toArray() does not return all the elements in the collection.: TestPerson("Bender").compareTo(TestPerson("Fry")) == 0 expected:true but was:false
at inf1010.assignment.IfiCollectionTest.assertCompareToEquals(IfiCollectionTest.java:74)
at inf1010.assignment.IfiCollectionTest.assertCompareToEquals(IfiCollectionTest.java:83)
at inf1010.assignment.IfiCollectionTest.assertCompareToEqualsNoOrder(IfiCollectionTest.java:100)
at inf1010.assignment.IfiCollectionTest.toArray(IfiCollectionTest.java:202)
protected void assertCompareToEquals(TestPerson actual,
TestPerson expected, String msg) {
assertTrue(actual.compareTo(expected) == 0, String.format( // l:74
"%s: %s.compareTo(%s) == 0", msg, actual, expected));
}
[...]
protected void assertCompareToEquals(TestPerson[] actual,
TestPerson[] expected, String msg) {
for (int i = 0; i < actual.length; i++) {
TestPerson a = actual[i];
TestPerson e = expected[i];
assertCompareToEquals(a, e, msg); // l:83
}
}
[...]
protected void assertCompareToEqualsNoOrder(TestPerson[] actual,
TestPerson[] expected, String msg) {
assertEquals(actual.length, expected.length, msg);
TestPerson[] actualElements = new TestPerson[actual.length];
System.arraycopy(actual, 0, actualElements, 0, actual.length);
TestPerson[] expectedElements = new TestPerson[expected.length];
System.arraycopy(expected, 0, expectedElements, 0, expected.length);
Arrays.sort(expectedElements);
Arrays.sort(actualElements);
assertCompareToEquals(actualElements, expectedElements, msg); // l:100
}
[...]
#Test(dependsOnGroups = { "collection-core" },
description="Tests if method toArray yields all the elements inserted in the collection in sorted order with smallest item first.")
public void toArray() {
TestPerson[] actualElements = c.toArray(new TestPerson[c.size()]);
for (int i = 0; i < actualElements.length; i++) {
assertNotNull(actualElements[i],
"toArray() - array element at index " + i + " is null");
}
TestPerson[] expectedElements = allElementsAsArray();
assertCompareToEqualsNoOrder(actualElements, expectedElements, // l:202
"toArray() does not return all the elements in the collection.");
Arrays.sort(expectedElements);
assertCompareToEquals(actualElements, expectedElements,
"toArray() does not return the elements in sorted order with "
+ "the smallest elements first.");
TestPerson[] inArr = new TestPerson[NAMES.length + 1];
inArr[NAMES.length] = new TestPerson("TEMP");
actualElements = c.toArray(inArr);
assertNull(actualElements[NAMES.length],
"The the element in the array immediately following the "
+ "end of the list is not set to null");
}
I don't know if I should post more of the test code, it's quite extensive, and it might be a little too much for one post?
Ok, I think the problem is your use of the "global" variable current. The way it is set, doesn't make much sense. You don't need to anyway, because the "current" Node is the one that is provided in the parameters.
Also you should consider renaming your function. You aren't sorting anything here, just collecting the contents of the tree, so a name such as collect would be more suitable.
public E[] toArray(E[] a) {
Node n = root;
a = collect(n, a);
return a;
}
public E[] collect(Node n, E[] a) {
if (n.left != null) {
// If there is a left (smaller) value, we go there first
collect(n.left, a);
}
// Once we've got all left (smaller) values we can
// collect the value of out current Node.
a[i] = n.obj;
i++;
if (n.right != null) {
// And if there is a right (larger) value we get it next
collect(n.right, a);
}
return a;
}
(Disclaimer: I haven't tested this)
Alternative implementation without the global index:
public E[] toArray(E[] a) {
Node n = root;
collect(n, a, 0);
return a;
}
public int collect(Node n, E[] a, int i) {
if (n.left != null) {
// If there is a left (smaller) value, we go there first
i = collect(n.left, a, i);
}
// Once we've got all left (smaller) values we can
// collect the value of out current Node.
a[i] = n.obj;
i++;
if (n.right != null) {
// And if there is a right (larger) value we get it next
i = collect(n.right, a, i);
}
return i;
}
I see you have the code
if (n.left != null) {
current = n.left;
sort(current, a);
}
but I can't seem to find at which point you set current back at the current node so that when you do
a[i] = current.obj;
you get the correct result. That's probably why you're not getting all the results. In any case I don't see (at least from the code fragments you have posted) why current needs to be a class variable and not just declared in the sort method. In general you shouldn't be using class variables if you don't really need them.
Edit:
You can either set current back to the node you are processing after calling sort on the left child like this
current = n;
a[i] = current.obj;
i++;
Or not use current at all in which case you'd have something like
if (n.left != null)
sort(n.left, a);
a[i] = n.obj;
i++;
if (n.right != null)
sort(n.right, a);
I think where you are confused is that if you check out how a binary search tree works, is that it is always sorted. You start at your root node, and then as you insert a new node, it inserts it into the appropriate position (i.e. to the left or the right) depending on the values. So you should not have to call sort to begin with. So I would start there, and read up on binary search trees. For example wikipedia has a decent article.
Update: Ignore my comment you should not need to do that either. Say you insert 8, 3, 7, 9, 12, 2, 10, 1 into the tree in that order. It should end up looking like this:
8
/ \
3 9
/ \ \
2 7 12
/ /
1 10
If you look at it that means to get them in order, start at the root, then if it has a node to the left got to the left, if not, return itself, and go to the right if it has a value. Repeating this for each node you encounter.
http://cs.armstrong.edu/liang/intro8e/html/BinaryTree.html
The easiest way to do what you are looking for is to traverse the tree inorder and append to an ArrayList. To get the array you can call the .toArray() method of the arrayList.
If you can't use an arraylist, declare an index and an array outside the inordertraversal and increment, you will need to know how many elements are in the tree to declare your array.
pseudo code:
variables:
arraysize = root.count()
E[] inOrderNodeArray = new E[arraysize]
int index = 0
inorder traversal:
void inorder(Node n) {
if (n) {
inorder(n.left)
inOrderNodeArray[index] = n
index++
inorder(n.right)
}
}