Related
Given the alphabet and a morse code value for each letter...
a._
b_...
c_._.
d_.. //file to be read in
e.
f.._.
I'm attempting to create a tree, finding the position for a letter in the tree by scanning the code, and branching left for a dot and branching right for a dash.
I've created a node class with the typical numberNode left and numberNode right variables along with morseCode and letter. Here's my function.
aList is an arraylist of created nodes read in from a file. rootNode is the root of the tree, having no set letter or morsecode.
public static void createTree(ArrayList<numberNode> aList, numberNode rootNode)
{
for (numberNode n : aList) //for each numberNode in aList
{
int lengthOfCode = n.getmorseCode().length()-1; //get the length of the morsecode
numberNode currentNode = rootNode; //sets currentNode to the rootNode at first
for (int i=0; i<lengthOfCode; i++)
{
char c = n.getmorseCode().charAt(i); //for each char in morsecode until it gets to the end
if (c == '.')
{
if (currentNode.getleft() = null) //if currentnode left is null
{
numberNode newLeftNode = new numberNode(); //create new node
currentNode.setleft(newLeftNode); //set current node left to the new node
if (i == lengthOfCode)
{
currentNode.setleft(n); //if end of morse code, set the current node left's to n
}
else
{
currentNode = newLeftNode; //else change current node to the newly created leftnode
}
}
else //if current node left is not null
{
if (i == lengthOfCode)
{
currentNode.setleft(n); //if at end of morse code
}
currentNode = currentNode.getleft(); //if not at end set current node to current node's left
}
}
if (c == '_')
{
if (currentNode.right() =null)
{
numberNode newRightNode = new numberNode();
currentNode.setleft(newRightNode);
if (i == lengthOfCode)
{
currentNode.setright(n);
}
else
{
currentNode = newRightNode;
}
}
else
{
if (i == lengthOfCode)
{
currentNode.setright(n);
}
currentNode = currentNode.getright();
}
}
}
}
}
Couple questions I have...
Is my algorithm at least correct?
Is there an alternate way of doing this without it being so ugly?
If you need to see any more of my code please don't hesitate to ask. Thanks for your time, I truly appreciate it!
EDIT: Currently runs, but when I try to print out the output using...
for (numberNode n : nodeArray)
{
System.out.println(n.getletter());
System.out.println(n.getleft().getletter().toString()); //error here
System.out.println(n.getright().getletter());
System.out.println("");
}
I get an error where indicated,Any ideas on what's going wrong?
First, when you try to print the values out, what did the compiler say was the error on System.out.println(n.getleft().getletter().toString()); //error here?
Is each letter suppose to be the root of it's own tree? If it is suppose to be on tree, I would have a reference pointer at the start that would contain references to every letter in the alphabet, while the nodes branching off each letter would have the particular sequence that represents the Morse code for that letter. But if I was free to do whatever, I would simply create an array of 26 characters that contain a MorseCode object that has two fields, one containing the Letter and the other containing the Morse Code that is associated with that letter.
It would be helpful to understand what the output is suppose to be for this program and clarify what is in the file you are reading into the arrayList. What does that data look like?
YES, this is a homework project.
That being said, I'm looking to learn from my mistakes rather than just have someone do it for me.
My project is a word frequency list - I accept a text file (or website URL) and count the:
- Number of unique words, and
- How many times they appear.
All methods are provided for me except for one: the insert(E word) method, where the argument is a generic type word.
The word is stored in a Node (Linked List project) that also has a 'count' value, which is the value representing the number of times the word appears in the text being read.
What this method has to do is the following:
If the argument is already in the list, increment the count of that element. I have done this part
If the argument is not found in the list, append it to the list. I also have done this part.
sort the list by descending count value. i.e. highest -> lowest count
3.5. If two elements have the same count value, they are sorted by the dictionary order of their word.
I am VERY unfamiliar with Linked Lists, so as such I am running into a lot of NullPointerExceptions. This is my current insert method:
public void insert(E word){
if(word.equals("")){
return;
}
if(first == null){//if list is null (no elements)
/*Node item = new Node(word);
first = item;*/
first = new Node(word);
}
else{//first != null
Node itemToAdd = new Node(word);
boolean inList = false;
for(Node x = first; x != null; x=x.next){
if (x.key.equals(word)){// if word is found in list
x.count++;//incr
inList = true;//found in list
break;//get out of for
}//end IF
if(x.next == null && inList == false){//if end of list && not found
x.next = itemToAdd;//add to end of list
break;
}//end IF
}//end FOR
//EVERYTHING ABOVE THIS LINE WORKS.
if (!isSorted()){
countSort();
}
}//end ELSE
}//end method
My isSorted() method:
public boolean isSorted(){
for(Node copy = first; copy.next != null; copy = copy.next){
if (copy.count < copy.next.count){
return false;
}
}
return true;
}
and last but not least, the part where I'm struggling, the sort method:
public void countSort(){
for (Node x = first, p = x.next; p != null; x=x.next, p=p.next){
// x will start at the first Node, P will always be 1 node ahead of X.
if(x == first && (x.count < p.count)){
Node oldfirst = first;
x.next = p.next;
first = p;
first.next = oldfirst;
break;
}
if (x.count < p.count){
//copy.next == x.
Node oldfirst = first;
oldfirst.next = first.next;
x.next = p.next;
first = p;
first.next = oldfirst;
break;
}
if (x.count == p.count){
if(x.toString().charAt(0) < p.toString().charAt(0)){
//[x]->[p]->[q]
Node oldfirst = first;
x.next = p.next;
first = p;
first.next = oldfirst;
break;
}
}
}
}
Here is the output of my insert method when called by the classes/methods given to me:
Elapsed time:0.084
(the,60)
(of,49)
(a,39)
(is,46)
(to,36)
(and,31)
(can,9)
(in,19)
(more,7)
(thing,7)
(violent,3)
(things,3)
(from,9)
(collected,1)
(quotes,1)
(albert,1)
(einstein,2)
(any,2)
(intelligent,1)
(fool,1)
(make,1)
(bigger,1)
(complex,1)
(it,11)
(takes,1)
(touch,1)
(genius,1)
(lot,1)
(courage,1)
(move,1)
(opposite,1)
(direction,1)
(imagination,1)
(important,5)
(than,3)
(knowledge,3)
(gravitation,1)
(not,17)
(responsible,1)
(for,14)
(people,2)
(falling,1)
(love,2)
(i,13)
(want,1)
(know,3)
(god,4)
(s,8)
(thoughts,2)
(rest,2)
(are,11)
(details,2)
(hardest,1)
(world,7)
(understand,3)
(income,1)
(tax,1)
(reality,3)
(merely,1)
(an,7)
(illusion,2)
(albeit,1)
(very,3)
(persistent,2)
(one,12)
(only,7)
(real,1)
(valuable,1)
(intuition,1)
(person,1)
(starts,1)
(live,2)
(when,3)
(he,11)
(outside,1)
(himself,4)
(am,1)
(convinced,1)
(that,14)
(does,5)
(play,2)
(dice,1)
(subtle,1)
(but,8)
(malicious,1)
(weakness,2)
(attitude,1)
(becomes,1)
(character,1)
(never,3)
(think,1)
(future,2)
(comes,1)
(soon,1)
(enough,1)
(eternal,1)
(mystery,1)
(its,4)
(comprehensibility,1)
(sometimes,1)
My initial idea has been to try and loop the if(!isSorted()){ countSort();} part to just repeatedly run until it's sorted, but I seem to run into an infinite loop when doing that. I've tried following my professor's lecture notes, but unfortunately he posted the previous lecture's notes twice so I'm at a loss.
I'm not sure if it's worth mentioning, but they provided me an iterator with methods hasNext() and next() - how can I use this as well? I can't imagine they'd provide it if it were useless.
Where am I going wrong?
You are close. First the function to compare the items is not complete, so isSorted() could yield wrong results (if the count is the same but the words are in wrong order). This is also used to sort, so it's best to extract a method for the comparison:
// returns a value < 0 if a < b, a value > 0 if a > b and 0 if a == b
public int compare(Node a, Node b) {
if (a.count == b.count)
return a.word.compareTo(b.word);
// case-insensitive: a.word.toLoweCase().compareTo(b.word.toLowerCase())
} else {
return a.count - b.count;
}
}
Or simplified which is enough in your case:
public boolean correctOrder(Node a, Node b) {
if (a.count > b.count)
return true;
else if (a.count < b.count)
return false;
else
return a.word.compareTo(b.word) <= 0;
}
For the sort you seem to have chosen bubble sort, but you are missing the outer part:
boolean change;
do {
change = false;
Node oldX = null;
// your for:
for (Node x = first; x.next != null; x = x.next) {
if (!correctOrder(x, x.next)) {
// swap x and x.next, if oldX == null then x == first
change = true;
}
oldX = x;
}
} while (change);
We could use the help of Java native library implementation or more efficient sort algorithms, but judging from the exercise the performance of the sort algorithm is of no concern yet, first need to grasp basic concepts.
With looking your codes, it sounds like to me that two things can be done:
Firstly, you can make use of Comparable class method. So, I assume you wrote the class Node, thus you may want to inherit from Comparable class. When you inherited from that class, java will automatically provide you the compareTo method, and all you need to do is to specify in that method that "I want to compare according to your counts and I want it to be in ascending order."
**Edit(1):By the way, I forgot the mention before but after you impelement your compareTo method, you can use Collections.sort(LinkedList list), and it will be done.
The second solution came to mind is that you can sort your list during the countSort() operation with the technique of adding all to an another list with sorting and after add all them back to the real list. The sorting technique I'm trying to say is, keep going towards to the end of the list until you find a Node in the list that has a count smaller than currently adding Node's counts. Hope that doesn't confuse your head, but by this way you can achieve more clear method and less complicated view. To be clear I want to repeat the procedure:
Look the next
If (next is null), add it //You are at the end.
else{
if (count is smaller than current count), add it there
else, keep moving to the next Node. //while can be used for that.
}
I would like to display the tree structure level by level. My current code does a BFS or Level Order Traversal but I cannot get the output to display the tree structure like a tree
See current output and Expected output.
My idea was to use some kind of count to iterate over elements from the same level in the queue.
How can I do so.
Original Code without this function can be found in the link below in case someone needs the entire implementation else just look at the displayBFS function below.
Level Order traversal of a generic tree(n-ary tree) in java
Thanks!
void displayBFS(NaryTreeNode n)
{
Queue<NaryTreeNode> q = new LinkedList<NaryTreeNode>();
System.out.println(n.data);
while(n!=null)
{
for(NaryTreeNode x:n.nary_list)
{
q.add(x);
System.out.print(x.data + " ");
}
n=q.poll();
System.out.println();
}
}
Current Tree Structure for reference:
root(100)
/ | \
90 50 70
/ \
20 30 200 300
Current Output:
100
90 50 70
20 30
200 300
Expected Output
100
90 50 70
20 30 200 300
Also, I had posted a logic issue with the same function earlier, as that was answered and the current question realtes to a different problem, I posted a new question, is this approach okay or should I make edits to the earlier question and not open a new one?
only need to keep track of current level and next level.
static void displayBFS(NaryTreeNode root) {
int curlevel = 1;
int nextlevel = 0;
LinkedList<NaryTreeNode> queue = new LinkedList<NaryTreeNode>();
queue.add(root);
while(!queue.isEmpty()) {
NaryTreeNode node = queue.remove(0);
if (curlevel == 0) {
System.out.println();
curlevel = nextlevel;
nextlevel = 0;
}
for(NaryTreeNode n : node.nary_list) {
queue.addLast(n);
nextlevel++;
}
curlevel--;
System.out.print(node.data + " ");
}
}
when you switch levels, swap nextlevel for currentlevel and reset nextlevel. i prefer the simplicity of this over keeping a whole separate queue.
i had this question for a microsoft interview last week... it didn't go so well for me over the phone. good on you for studying it.
The simplest solution I know of to this problem is to use a sentinel. The queue is initialized with the root node followed by the sentinel, and then you loop through the queue:
remove the front element
if it is the sentinel:
we're at the end of a level, so we can end the output line
if the queue is not empty, push the sentinel back onto the queue at the end.
if it is not the sentinel:
print it out
push all its children onto the queue.
I don't do Java, but I have some C++ code for depth-aware BFS, which I stripped down to do this printing task:
void show_tree_by_levels(std::ostream& os, Node* tree) {
Node* sentinel = new Node;
std::deque<Node*> queue{tree, sentinel};
while (true) {
Node* here = queue.front();
queue.pop_front();
if (here == sentinel) {
os << std::endl;
if (queue.empty())
break;
else
queue.push_back(sentinel);
} else {
for (Node* child = here->child; child; child = child->sibling)
queue.push_back(child);
os << here->value << ' ';
}
}
}
Note that I prefer to use a two-pointer solution (first_child/next_sibling), because it usually works out to be simpler than embedded lists. YMMV.
Use another queue to indicate depth.
The below code is not tested, but it should give you the idea (the sep variable is introduced to avoid trailing white-spaces):
void displayBFS(NaryTreeNode n) {
Queue<NaryTreeNode> q = new LinkedList<NaryTreeNode>();
Queue<Integer> depth = new LinkedList<Integer>();
q.add(n);
depth.add(0);
String sep = "";
int oldDepth = 0
while(!q.isEmpty()) {
NaryTreeNode currN = q.poll();
int currDepth = depth.poll();
if (currDepth > oldDepth) {
System.out.println();
oldDepth = currDepth;
sep = "";
}
System.out.print(sep + currN.data);
sep = " ";
for(NaryTreeNode x : currN.nary_list) {
q.add(x);
depth.add(currDepth + 1);
}
}
}
For my taste this approach is more self-explanatory compared to other ways one could do it.
I think we need three more variables. numInCurrentLevel for keeping track of the number of elements in current level, indexInCurrentLevel for doing the count when traversal in current level and numInNextLevel for keeping track of the number of elements in next level. The code is below:
static void displayBFS(NaryTreeNode root) {
Queue<NaryTreeNode> q = new LinkedList<NaryTreeNode>();;
q.add(root);
int numInCurrentLevel = 1;
int numInNextLevel = 0;
int indexInCurrentLevel=0;
while(!q.isEmpty()) {
NaryTreeNode node = q.poll();
System.out.print(node.data + " ");
indexInCurrentLevel++;
for(NaryTreeNode n : node.nary_list) {
q.add(n);
numInNextLevel++;
}
//finish traversal in current level
if(indexInCurrentLevel==numInCurrentLevel) {
System.out.println();
numInCurrentLevel=numInNextLevel;
numInNextLevel=0;
indexInCurrentLevel=0;
}
}
}
Hope it helps, I am not so familiar with java programming.
def printLevelWiseTree(tree):
q= queue.Queue()
if tree == None:
return None
q.put(tree)
while (not(q.empty())):
c = q.get()
print(c.data,end=":")
for i in range(len(c.children)):
if i != len(c.children)-1:
print(c.children[i].data,end=",")
else:
print(c.children[i].data,end="")
q.put(c.children[i])
print()
I want to be up front so I will say this homework that I am about to talk about. We are suppose to do a B+ tree. I've got it most of the way there but I am having a problem when I have a node split. Specifically when the node is a non-leaf (excluding the root) and it splits I am losing my far right pointer.
For example if the tree was
|3 5|
|1 2| |4| |5 6|
I lose the pointer to |5 6|. So when I search for those values I cannot find them or when I go to add a value that would follow that path I get a null pointer exception.
Anyway I normally would just paste my code here but, unfortunately, we have developed a problem with cheating in my school and since the program is due soon, I am sure a lot of my classmates are scouring the internet for the code. The last thing I want to happen is some jerk rip off my code.
If anyone wouldn't mind looking at the code I will gladly send it to you to check out. Once again it is in Java and is pretty lengthy.
Thanks in advance.
Here is the code. On a side node When I clear offsets and keys I use int and long MAX_VALUE so when I sort I know those cleared values will go to the end of the node. The Split class is just a dumb idea from earlier I need to fix. It consists of a node, offset, and key. Originally I was thinking that I may need to return an offset and key that wasn't in the split node. I then realized that was dumb and all I would ever need to return was the new node itself.
public void add (int key, long offset) throws IOException
{
if (root != null) //start search of where to add the book
{
SplitBucket split = add(root, key, offset); //recursive call
if (split != null) //root has split
{
long newRootOffset;
//make new root and have it point to old root and the split node
BookNode newRoot = new BookNode();
newRoot.changeCurrentChildren(1);
newRoot.setChildKey(0, split.key);
newRoot.setChildOffset(0, root.getMyOffset());
newRoot.setChildOffset(1, split.offset);
newRoot.setChildOffset(2,
root.getChildOffset(Constants.childSize -1));
newRoot.setNode(0, root);
newRoot.setNode(1, split.node);
newRoot.setNode(2, root.getNode(Constants.childSize - 1));
io.setBookNode(root.getMyOffset(), root);
newRootOffset = io.insertNewNode(newRoot);
io.setRoot(newRootOffset);
root = newRoot;
}
}
else //empty tree so create root and add
{
long rootOffset = Long.MAX_VALUE;
root = new BookNode();
root.setChildKey(0, key);
root.setChildOffset(0, offset);
root.changeCurrentChildren(1);
root.switchLeaf(true);
rootOffset = io.insertNewNode(root);
io.setRoot(rootOffset);
root.setMyOffset(rootOffset);
}
}
/**
*
* #param current current BookNode
* #param key Isbn to add
* #param offset offset of Book to add
* #return BookNode if a split occurs
* #throws IOException
*/
private SplitBucket add (BookNode current, int key, long offset)
throws IOException
{
if (current.isLeaf()) // at the bottom level
{
//room to add
if (current.getCurrentChildren() < Constants.childSize - 1)
{
//add the offset and key to the end of the node.
//sort the node and rewrite to file
current.setChildOffset(current.getCurrentChildren(), offset);
current.setChildKey(current.getCurrentChildren(), key);
current.changeCurrentChildren(1);
current.sortKeysAndOffsets();
io.setBookNode(current.getMyOffset(), current);
return null;
}
else //not enough room must split
{ //add offset and key to end of node and sort
current.setChildKey(current.getCurrentChildren(), key);
current.setChildOffset(current.getCurrentChildren(), offset);
current.changeCurrentChildren(1);
current.sortKeysAndOffsets();
int start = current.getCurrentChildren() / 2;
long newNodeOffset =Long.MAX_VALUE;
SplitBucket bucket = new SplitBucket();
BookNode newNode = new BookNode();
newNode.switchLeaf(true);
for(int i = start; i < Constants.childSize; i++)
{
//new node will hold the larger split values
newNode.setChildKey(i - start, current.getChildKey(i));
newNode.setChildOffset(i - start, current.getChildOffset(i));
newNode.setNode(i - start, current.getNode(i));
newNode.changeCurrentChildren(1);
current.setChildKey(i, Integer.MAX_VALUE);
current.setChildOffset(i, Long.MAX_VALUE);
current.setNode(i, null);
current.changeCurrentChildren(-1);
}
//since sorted prior to for loop all data
//needs not to be sorted again
newNode.sortKeysAndOffsets();
current.sortKeysAndOffsets();
//Transferring pre-split nodes 'next' pointer to new node
newNode.setChildOffset(Constants.childSize,
current.getChildOffset(Constants.childSize));
newNode.setNode(Constants.childSize,
current.getNode(Constants.childSize));
newNodeOffset = io.insertNewNode(newNode);
newNode.setMyOffset(newNodeOffset);
current.setChildOffset(Constants.childSize, newNodeOffset);
current.setNode(Constants.childSize, newNode);
io.setBookNode(current.getMyOffset(), current);
bucket.key = newNode.getChildKey(0);
bucket.offset = newNode.getMyOffset();
bucket.node = newNode;
return bucket;
}
}
else //not at a leaf
{
int index = 0;
//find pointer index to follow
while (index < current.getCurrentChildren()
&& key >= current.getChildKey(index))
{
index++;
}
//recursive call
SplitBucket bucket = add(current.getNode(index), key, offset);
if(bucket != null) //split occurred
{
//bucket not full so add here
if(current.getCurrentChildren() < Constants.childSize)
{
current.setChildKey(current.getCurrentChildren(), bucket.key);
current.setChildOffset(current.getCurrentChildren(),
bucket.offset);
current.setNode(current.getCurrentChildren(), bucket.node);
current.changeCurrentChildren(1);
current.sortKeysAndOffsets();
io.setBookNode(current.getMyOffset(), current);
bucket = null;
}
else //bucket is full so split
{
int start = current.getCurrentChildren() / 2;
long newNodeOffset = Long.MAX_VALUE;
BookNode newNode = new BookNode();
for(int i = start; i < Constants.childSize; i++)
{
//larger keys go to the new node
newNode.setChildKey(i - start, current.getChildKey(i));
newNode.setChildOffset(i - start,
current.getChildOffset(i));
newNode.setNode(i - start, current.getNode(i));
newNode.changeCurrentChildren(1);
current.setChildKey(i, Integer.MAX_VALUE);
current.setChildOffset(i, Long.MAX_VALUE);
current.setNode(i, null);
current.changeCurrentChildren(-1);
}
if(bucket.key > newNode.getChildKey(0)) //goes in new bucket
{
newNode.setChildKey(newNode.getCurrentChildren(),
bucket.key);
newNode.setChildOffset(newNode.getCurrentChildren(),
bucket.offset);
newNode.setNode(newNode.getCurrentChildren(),
bucket.node);
newNode.changeCurrentChildren(1);
newNode.sortKeysAndOffsets();
}
else //goes in old bucket
{
current.setChildKey(current.getCurrentChildren(),
bucket.key);
current.setChildOffset(current.getCurrentChildren(),
bucket.offset);
current.setNode(current.getCurrentChildren(),
bucket.node);
current.changeCurrentChildren(1);
current.sortKeysAndOffsets();
}
//may not need this line and next
newNode.setChildOffset(newNode.getCurrentChildren(),
current.getChildOffset(Constants.childSize));
newNode.setNode(newNode.getCurrentChildren(),
current.getNode(Constants.childSize));
newNodeOffset = io.insertNewNode(newNode);
newNode.setMyOffset(newNodeOffset);
io.setBookNode(current.getMyOffset(), current);
bucket = new SplitBucket();
//return middle key value of split node
bucket.key = newNode.getChildKey(
newNode.getCurrentChildren() /2);
bucket.offset = newNode.getMyOffset();
bucket.node = newNode;
return bucket;
}
}
}
return null;
}
Write a test case, or a 'main' method, for the test that fails. Then you can breakpoint & debug just that situation.
Put logging in your code, to output the important/ decisive information & things it's doing -- so you can see where it's going wrong.
Don't log uninteresting stuff -- log the API calls, which nodes are being created/ updated & which key ranges are being split. Log what really tells you what's going on.
If you don't like logging, you step thru & debug. It's not as efficient/ productive as using logging to debug & engineer your code, though.
I am trying to build a binary tree from a string input piped to System.in with Java. Whenever a letter from a-z is encountered in the string I am making an internal node (with 2 children). Whenever a 0 is encountered in the string I am making an external node (a leaf). The string is in preorder, so just as an example, if I had an input such as:
abcd000e000
I am supposed to make the following binary tree
a
/ \
b 0
/ \
c e
/ \ / \
d 00 0
/ \
0 0
At least that is what I think I am supposed to make according to the assignment details (in a link below). We were also given sample input and output for the entire program:
Input
a0
0
a00
ab000
Output
Tree 1:
Invalid!
Tree 2:
height: -1
path length: 0
complete: yes
postorder:
Tree 3:
height: 0
path length: 0
complete: yes
postorder: a
Tree 4:
height: 1
path length: 1
complete: yes
postorder: ba
I am trying to implement a program that will do this for me with Java, but I don't think I am making the binary tree correctly. I have provided the code I have come up with so far and detailed in the comments above each method what trouble I have run into so far while debugging. If more context is needed the following link details the entire assignment and what the ultimate goal is supposed to be (building the binary tree is only the first step, but I'm stuck on it):
Link to Assignment
import java.io.*;
// Node
class TreeNode {
char value;
TreeNode left;
TreeNode right;
}
// Main class
public class btsmall {
// Global variables
char[] preorder = new char[1000];
int i = 0;
// Main method runs gatherOutput
public static void main(String[] args) throws IOException {
new btsmall().gatherOutput();
}
// This takes tree as input from the gatherOutput method
// and whenever a 0 is encountered in the preorder character array
// (from a string from System.in) a new external node is created with
// a value of 0. Whenever a letter is encountered in the character
// array, a new internal node is created with that letter as the value.
//
// When I debug through this method, the tree "appears" to be made
// as expected as the tree.value is the correct value, though I
// can't check the tree.left or tree.right values while debugging
// as the tree variable seems to get replaced each time the condition
// checks restart.
public void createTree(TreeNode tree) throws IOException {
// Check that index is not out of bounds first
if (i >= preorder.length) {
i++;
} else if (preorder[i] == '0') {
tree = new TreeNode();
tree.value = '0';
tree.left = tree.right = null;
i++;
} else {
tree = new TreeNode();
tree.value = preorder[i];
i++;
createTree(tree.left);
createTree(tree.right);
}
}
// Supposed to print out contents of the created binary trees.
// Intended only to test that the binary tree from createTree()
// method is actually being created properly.
public void preorderTraversal(TreeNode tree) {
if (tree != null) {
System.out.println(tree.value + " ");
preorderTraversal(tree.left);
preorderTraversal(tree.right);
}
}
// Reads System.in for the Strings used in making the binary tree
// and is supposed to make a different binary tree for every line of input
//
// While debugging after the createTree method runs, the resulting tree variable
// has values of tree.left = null, tree.right = null, and tree.value has no value
// (it's just a blank space).
//
// This results in preorderTraversal printing out a single square (or maybe the square
// is some character that my computer can't display) to System.out instead of all
// the tree values like it's supposed to...
public void gatherOutput() throws IOException {
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(input);
String line = null;
TreeNode tree = new TreeNode();
while ((line = reader.readLine()) != null) {
preorder = line.toCharArray();
createTree(tree);
preorderTraversal(tree);
i = 0;
}
}
}
Can anyone help me with building the binary tree properly and point out what I am doing wrong that would result in the output I'm currently getting? Am I at least on the right track? Any hints?
Thanks.
EDIT:
Here's a picture of the "square" output (this is in Eclipse).
Your createTree() method ... doesn't create a tree.
You never attach internal nodes to anything ... you just create them, insert the value, then pass them to the next createTree() call (which does the same).
A quick fix can be a simple modification of your createTree(..) method,
public void createTree(TreeNode tree) throws IOException {
// Check that index is not out of bounds first
if (i >= preorder.length) {
i++;
} else if (preorder[i] == '0') {
tree.value = '0';
tree.left = tree.right = null;
i++;
} else {
tree.value = preorder[i];
i++;
tree.left = new TreeNode();
createTree(tree.left);
tree.right = new TreeNode();
createTree(tree.right);
}
}
Notice you were creating a TreeNode inside this method, whereas it was already passed as an argument. So, you were not at all using the same. Whatever you did was not in the original TreeNode passed.
NB: Not arguing about the correctness of binary tree. Just fix a problem in hand. This might help the OP.
but I don't think I am making the binary tree correctly
Yes, it is incorrect. In binary tree one sub-tree is "less" than current element, another one is "more". You have, for example, "b" as the parent for "c" and "e", while (if followed natural sorting) both "c" and "e" are "more".
You need to rebalance you tree in the process.
P.S. I don't know what zeros supposed to mean in the input, but if the input is limited the simplest way to build a binary tree from a sorted sequence is:
load whole sequence into an array
get middle element as the root one
repeat step 2 recursively for the sub-arrays on the left and right of the root element
Update
And yes, as stated in some other answer, you need to have something like:
} else if (preorder[i] == '0') {
TreeNode subTree = new TreeNode();
subTree.value = '0';
tree.rigth = subTree;
i++;
and then pass subTree into recursive call.
Also I see an implementation problem:
while ((line = reader.readLine()) != null) {
does not seem to be a correct stop condition. It will loop forever because if you press just enter, line will not be null, but an empty string.
This one is more suitable:
while (!(line = reader.readLine()).equals("")) {