Expression Tree printing - java

I'm working on an expression tree project at the moment that takes in a postfix expression from the user(i.e, 7 8 +) and stores it in an expression tree; the program should then print the tree in a typical tree format and present the user with the option to print out an infix, prefix, or postfix format.
As of now, it seems my tree is being properly instantiated, but every time I try to print it the format is slightly off and each operator/operand is duplicated. So, if the output should look like
-
6 5
it ends up looking like
- -
6 5 6 5
On top of that, whenever I try to print out an infix/prefix/postfix format, I run into several null pointer exceptions - and the way I wrote the code, I don't know how that is even possible.
The main method for printing out the tree is as follows:
public String toString() {
String result = "";
int printDepth = getHeight();
int possibleNodes = (int)Math.pow(2, printDepth+1);
int countNodes = 0;
UnorderedListADT<BTNode<ExpressionTreeNode>> nodes = new UnorderedList<BTNode<ExpressionTreeNode>>();
UnorderedListADT<Integer> levelList = new UnorderedList<Integer>();
BTNode<ExpressionTreeNode> current;
nodes.addToRear(root);
Integer currentLevel = 0;
Integer previousLevel = -1;
levelList.addToRear(currentLevel);
while(countNodes < possibleNodes) {
countNodes += 1;
current = nodes.removeFirst();
currentLevel = levelList.removeFirst();
if(currentLevel>previousLevel) {
result += "\n\n";
previousLevel = currentLevel;
for(int a=0;a<((Math.pow(2, (printDepth-currentLevel+1))-1));a++) {
result += " ";
}
}
if(current!=null) {
result += (current.getElement()).toString()+" ";
nodes.addToRear(current.getLeft());
levelList.addToRear(currentLevel+1);
nodes.addToRear(current.getRight());
levelList.addToRear(currentLevel+1);
}
else {
nodes.addToRear(null);
levelList.addToRear(currentLevel+1);
nodes.addToRear(null);
levelList.addToRear(currentLevel+1);
result += " ";
}
}
return result;
}
and the method for printing out the tree in various other formats...
public String printInorder() {
String result = "";
if(getLeft()!=null)
getLeft().printInorder();
result+= root.getElement()+" ";
if(getRight()!=null)//one null pointer occurs here
getRight().printInorder();//another occurs here
return result;
}
The methods for preorder and postorder are pretty much the same, they just change the order of result+=root.getElement()+" ";
I've tried reformatting these methods in all sorts of ways, but every time I just end up getting the same errors. I know that the entire tree isn't null, but what am I missing?
Any help would be greatly appreciated.

Related

java.lang.StringIndexOutOfBoundsException Error while reading Binary String

I have a long String with binary values. And i have a hash map that has the Binary digits as a key and char as a value. I have a function that supposed to read the binary string using 2 pointers and compare with hashmap and store the corresponding char in main.decodedTxt. However, im getting string out of bound exception for this. I don't know how to solve this. I'm getting exception on "String temp =" line. I have a picture link of the console output to see better picture.
public static void bitStringToText (String binText){
String bs = binText;
int from =0;
int to = 1;
while(bs != null){
String temp = bs.substring(from, to);
if (main.newMapDecoding.containsKey(temp)){
main.decodedTxt += main.newMapDecoding.get(temp);
from =to;
to = from +1;
} else {
to = to + 1;
}
}
}
Image of console exception is here
First of all there is no need to check if bs is null because no part of your code changes the value of bs. Your current code will cross the possible index of your binText at some point. It's better to loop just binText and check if you find something within it. After all you have to traverse the complete string anyways. Change your code as follows
public static void bitStringToText (String binText){
//no need to do this if you are not modifying the contents of binText
//String bs = binText;
int from =0;
int to = 1;
int size = binText.length();
String temp = "";
while(to <= size ){
temp = binText.substring(from, to);
if (main.newMapDecoding.containsKey(temp)){
main.decodedTxt += main.newMapDecoding.get(temp);
from =to;
to = from +1;
} else {
to = to + 1;
}
}
}
Hope it helps.
First, give it a try to practice debugging. It is an easy case. Either use run in debug mode (place break point on String temp = bs.substring(from, to); line) or print values of from and to before the same line. It will help to understand what is going on.
Solution:
If bs is not null you will always have StringIndexOutOfBoundsException. Because you are not checking if to is pointing to not existed index of bs String. Easiest example of the first one will be empty String: bs == "".
One of the solution could be to replace condition in while to while (to <= bs.length()).

What am I missing with this code? Google foo.bar

So recently I got invited to this google foo.bar challenge and I believe the code runs the way it should be. To be precise what I need to find is the number of occurrences of "abc" in a String. When I verify my code with them, I pass 3/10 test cases. I'm starting to feel bad because I don't know what I am doing wrong. I have written the code which I will share with you guys. Also the string needs to be less than 200 characters. When I run this from their website, I pass 3 tests and fail 7. Basically 7 things need to be right.
The actual question:
Write a function called answer(s) that, given a non-empty string less
than 200 characters in length describing the sequence of M&Ms. returns the maximum number of equal parts that can be cut from the cake without leaving any leftovers.
Example : Input : (string) s = "abccbaabccba"
output : (int) 2
Input: (string) s = "abcabcabcabc"
output : (int) 4
public static int answer(String s) {
int counter = 0;
int index;
String findWord ="ABC";
if(s!=null && s.length()<200){
s = s.toUpperCase();
while (s.contains(findWord))
{
index = s.indexOf(findWord);
s = s.substring(index + findWord.length(), s.length());
counter++;
}
}
return counter;
}
I see a couple of things in your code snippet:
1.
if(s.length()<200){
Why are you checking for the length to be lesser than 200? Is that a requirement? If not, you can skip checking the length.
2.
String findWord ="abc";
...
s.contains(findWord)
Can the test program be checking for upper case alphabets? Example: "ABC"? If so, you might need to consider changing your logic for the s.contains() line.
Update:
You should also consider putting a null check for the input string. This will ensure that the test cases will not fail for null inputs.
The logic of your code is well but on the other hand i found that you didn't check for if input string is empty or null.
I belief that google foo.bar wants to see the logic and the way of coding in a proper manner.
so don't be feel bad
I would go for a simpler approach
int beforeLen = s.length ();
String after = s.replace (findWord, "");
int afterLen = after.length ();
return (beforeLen - afterLen) / findWord.length ();
String pattern = "abc";
String line="<input text here>";
int i=0;
Pattern TokenPattern=Pattern.compile(pattern);
if(line!=null){
Matcher m=TokenPattern.matcher(line);
while(m.find()){
i++;
}}
System.out.println("No of occurences : "+ " "+i);
put declaration of index out before while block, isn't never good re-declare the same variable n time.
int index;
while (s.contains(findWord))
{
index = s.indexOf(findWord);
....
}
I hope this help
Update:
try to compact your code
public static int answer(String s) {
int counter = 0;
int index;
String findWord = "ABC";
if (s != null && s.length() < 200) {
s = s.toUpperCase();
while ((index = s.indexOf(findWord)) > -1) {
s = s.substring(index + findWord.length(), s.length());
counter++;
}
}
return counter;
}
Update:
The logic seems good to me, I'm still try to improve the performance, if you can try this
while ((index = s.indexOf(findWord, index)) > -1) {
//s = s.substring(index + findWord.length(), s.length());
index+=findWord.length();
counter++;
}

Java Recursive Decompression Program Doesn't Finish

I am trying to make a program to decompress a string that was compressed using RLE. The decompression program, however, must be written recursively, without loops, and without declaring variables outside the method. Below is my closest attempt so far, I am able to get the first "piece" of the compressed string (ex: 4w, q, g, J, 6y, etc.) decompressed. It just won't print out anything else after that, and I'm having trouble understanding why. much thanks
public class StringRec{
public static void main(String[] a){
System.out.println("string: ");
String decomp = IO.readString();
System.out.println(decompress(decomp));
}
public static String decompress(String compressedText){
int count = compressedText.length();
String index = "";
if(count == 0){
return "";
}
I though to make a few conditions that don't call the decompress method again,
because the condition for them is that they are the last piece in the string, so after their part is decompressed its done. Naturally, there calling would occur at the end of the runtime, after the other conditions with the decompress call have been called. Not sure why it isn't working.
else{
if(Character.isDigit(compressedText.charAt(0))){
String s = String.format("%0" + compressedText.charAt(0) + "d", 0).replace('0', compressedText.charAt(1));
index = s;
compressedText = compressedText.substring(2);
decompress(compressedText);
}
else if(Character.isDigit(compressedText.charAt(0)) && compressedText.length()==2){
String s2 = String.format("%0" + compressedText.charAt(0) + "d", 0).replace('0', compressedText.charAt(1));
index = s2;
}else if(Character.isLetter(compressedText.charAt(0))){
String s3 = Character.toString(compressedText.charAt(0));
index = s3;
compressedText = compressedText.substring(1);
decompress(compressedText);
}
else if(Character.isLetter(compressedText.charAt(0)) && compressedText.length()==1){
String s4 = Character.toString(compressedText.charAt(0));
index = s4;
}
return index;
}
}
My current guesses are that it has something to do with how the decompress method is called, or its a problem with how I arrange the output to be returned after the decompress method is already called, but then I wouldn't be able to explain how the first part of the string works consistently.
Try this.
public static String decompress(String compressedText) {
int count = compressedText.length();
if (count == 0) {
return "";
} else if (Character.isDigit(compressedText.charAt(0))) {
String s = String.format("%0" + compressedText.charAt(0) + "d", 0)
.replace('0', compressedText.charAt(1));
return s + decompress(compressedText.substring(2));
} else if (Character.isLetter(compressedText.charAt(0))) {
String s3 = Character.toString(compressedText.charAt(0));
return s3 + decompress(compressedText.substring(1));
} else
return compressedText;
}
It is not working because you forgot to 'concatenate' the result of the recursive decompress calls with the current index variable value. Because of this you 'drop' the results of the recursive calls and only have the result of the first call.
If you modify the decompress(compressedText) lines with index = index + decompress(compressedText) in your code, your results will be what you would expect.
(Btw, you should rename the topic to something like 'Java Recursive Decompression Program does not get the expected result' because from the title I would expect some code which produces infinite recursive calls :) )

Java codingbat help - withoutString

I'm using codingbat.com to get some java practice in. One of the String problems, 'withoutString' is as follows:
Given two strings, base and remove, return a version of the base string where all instances of the remove string have been removed (not case sensitive).
You may assume that the remove string is length 1 or more. Remove only non-overlapping instances, so with "xxx" removing "xx" leaves "x".
This problem can be found at: http://codingbat.com/prob/p192570
As you can see from the the dropbox-linked screenshot below, all of the runs pass except for three and a final one called "other tests." The thing is, even though they are marked as incorrect, my output matches exactly the expected output for the correct answer.
Here's a screenshot of my output:
And here's the code I'm using:
public String withoutString(String base, String remove) {
String result = "";
int i = 0;
for(; i < base.length()-remove.length();){
if(!(base.substring(i,i+remove.length()).equalsIgnoreCase(remove))){
result = result + base.substring(i,i+1);
i++;
}
else{
i = i + remove.length();
}
if(result.startsWith(" ")) result = result.substring(1);
if(result.endsWith(" ") && base.substring(i,i+1).equals(" ")) result = result.substring(0,result.length()-1);
}
if(base.length()-i <= remove.length() && !(base.substring(i).equalsIgnoreCase(remove))){
result = result + base.substring(i);
}
return result;
}
Your solution IS failing AND there is a display bug in coding bat.
The correct output should be:
withoutString("This is a FISH", "IS") -> "Th a FH"
Yours is:
withoutString("This is a FISH", "IS") -> "Th a FH"
Yours fails because it is removing spaces, but also, coding bat does not display the correct expected and run output string due to HTML removing extra spaces.
This recursive solution passes all tests:
public String withoutString(String base, String remove) {
int remIdx = base.toLowerCase().indexOf(remove.toLowerCase());
if (remIdx == -1)
return base;
return base.substring(0, remIdx ) +
withoutString(base.substring(remIdx + remove.length()) , remove);
}
Here is an example of an optimal iterative solution. It has more code than the recursive solution but is faster since far fewer function calls are made.
public String withoutString(String base, String remove) {
int remIdx = 0;
int remLen = remove.length();
remove = remove.toLowerCase();
while (true) {
remIdx = base.toLowerCase().indexOf(remove);
if (remIdx == -1)
break;
base = base.substring(0, remIdx) + base.substring(remIdx + remLen);
}
return base;
}
I just ran your code in an IDE. It compiles correctly and matches all tests shown on codingbat. There must be some bug with codingbat's test cases.
If you are curious, this problem can be solved with a single line of code:
public String withoutString(String base, String remove) {
return base.replaceAll("(?i)" + remove, ""); //String#replaceAll(String, String) with case insensitive regex.
}
Regex explaination:
The first argument taken by String#replaceAll(String, String) is what is known as a Regular Expression or "regex" for short.
Regex is a powerful tool to perform pattern matching within Strings. In this case, the regular expression being used is (assuming that remove is equal to IS):
(?i)IS
This particular expression has two parts: (?i) and IS.
IS matches the string "IS" exactly, nothing more, nothing less.
(?i) is simply a flag to tell the regex engine to ignore case.
With (?i)IS, all of: IS, Is, iS and is will be matched.
As an addition, this is (almost) equivalent to the regular expressions: (IS|Is|iS|is), (I|i)(S|s) and [Ii][Ss].
EDIT
Turns out that your output is not correct and is failing as expected. See: dansalmo's answer.
public String withoutString(String base, String remove) {
String temp = base.replaceAll(remove, "");
String temp2 = temp.replaceAll(remove.toLowerCase(), "");
return temp2.replaceAll(remove.toUpperCase(), "");
}
Please find below my solution
public String withoutString(String base, String remove) {
final int rLen=remove.length();
final int bLen=base.length();
String op="";
for(int i = 0; i < bLen;)
{
if(!(i + rLen > bLen) && base.substring(i, i + rLen).equalsIgnoreCase(remove))
{
i +=rLen;
continue;
}
op += base.substring(i, i + 1);
i++;
}
return op;
}
Something things go really weird on codingBat this is just one of them.
I am adding to a previous solution, but using a StringBuilder for better practice. Most credit goes to Anirudh.
public String withoutString(String base, String remove) {
//create a constant integer the size of remove.length();
final int rLen=remove.length();
//create a constant integer the size of base.length();
final int bLen=base.length();
//Create an empty string;
StringBuilder op = new StringBuilder();
//Create the for loop.
for(int i = 0; i < bLen;)
{
//if the remove string lenght we are looking for is not less than the base length
// and the base substring equals the remove string.
if(!(i + rLen > bLen) && base.substring(i, i + rLen).equalsIgnoreCase(remove))
{
//Increment by the remove length, and skip adding it to the string.
i +=rLen;
continue;
}
//else, we add the character at i to the string builder.
op.append(base.charAt(i));
//and increment by one.
i++;
}
//We return the string.
return op.toString();
}
Taylor's solution is the most efficient one, however I have another solution that is a naive one and it works.
public String withoutString(String base, String remove) {
String returnString = base;
while(returnString.toLowerCase().indexOf(remove.toLowerCase())!=-1){
int start = returnString.toLowerCase().indexOf(remove.toLowerCase());
int end = remove.length();
returnString = returnString.substring(0, start) + returnString.substring(start+end);
}
return returnString;
}
#Daemon
your code works. Thanks for the regex explanation. Though dansalmo pointed out that codingbat is displaying the intended output incorrectly, I through in some extra lines to your code to unnecessarily account for the double spaces with the following:
public String withoutString(String base, String remove){
String result = base.replaceAll("(?i)" + remove, "");
for(int i = 0; i < result.length()-1;){
if(result.substring(i,i+2).equals(" ")){
result = result.replace(result.substring(i,i+2), " ");
}
else i++;
}
if(result.startsWith(" ")) result = result.substring(1);
return result;
}
public String withoutString(String base, String remove){
return base.replace(remove,"");
}

Java - Most efficient way to convert string to double

Hi I am reading from a text file and saving each line (split by a comma) into an array. The only problem is that most of the elements in the array are double values where as two elements are strings. As a result of this I had to make the array a String[] array. Due to this, whenever I want to perform some equations on the double values in the array, I have to first parse them as a double value. I am literally running 1000+ iterations of these equations, therefore my code is constantly parsing the strings into a double. This is a costly way which is slowing down my program. Is there a better way I can convert the values from the string array to double values or is there a better approach I should take when saving the lines from the text file? Thanks
Here is what one of the arrays looks like after I have read from the text file:
String[] details = {"24.9", "100.0", "19.2" , "82.0", "Harry", "Smith", "45.0"};
I now need to multiply the first 2 elements and add that to the sum of the 3rd, 4th and 7th elements. In other words I am only using the numerical elements (that are ofcourse saved as strings)
double score = (Double.parseDouble(details[0]) * Double.parseDouble(details[1])) + Double.parseDouble(details[2]) + Double.parseDouble(details[3]) + Double.parseDouble(details[6]);
I have to do this for every single line in the text file (1000+ lines). As a result of this my program is running very slowly. Is there a better way I can convert the string values into a double? or is there a better way I should go about storing them in the first place?
EDIT: I have used profiler to check which part of the code is the slowest and it is indeed the code that I have shown above
Here's an example of generating an input file like the one you describe that's 10000 lines long, then reading it back in and doing the calculation you posted and printing the result to stdout. I specifically disable any buffering when reading the file in order to get the worst possible read performance. I'm also not doing any caching at all, as others have suggested. The entire process, including generating the file, doing the calculation, and printing the results, consistently takes around 520-550 ms. That's hardly "slow", unless you're repeating this same process for hundreds or thousands of files. If you see drastically different performance from this, then maybe it's a hardware problem. A failing hard disk can drop read performance to nearly nothing.
import java.io.*;
import java.util.Random;
public class ReadingDoublesFromFileEfficiency {
private static Random random = new Random();
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
String filePath = createInputFile();
BufferedReader reader = new BufferedReader(new FileReader(filePath), 1);
String line;
while ((line = reader.readLine()) != null) {
String[] details = line.split(",");
double score = (Double.parseDouble(details[0]) * Double.parseDouble(details[1])) + Double.parseDouble(details[2]) + Double.parseDouble(details[3]) + Double.parseDouble(details[6]);
System.out.println(score);
}
reader.close();
long elapsed = System.currentTimeMillis() - start;
System.out.println("Took " + elapsed + " ms");
}
private static String createInputFile() throws IOException {
File file = File.createTempFile("testbed", null);
PrintWriter writer = new PrintWriter(new FileWriter(file));
for (int i = 0; i < 10000; i++) {
writer.println(randomLine());
}
writer.close();
return file.getAbsolutePath();
}
private static String randomLine() {
return String.format("%f,%f,%f,%f,%s,%s,%f",
score(), score(), score(), score(), name(), name(), score());
}
private static String name() {
String name = "";
for (int i = 0; i < 10; i++) {
name += (char) (random.nextInt(26) + 97);
}
return name;
}
private static double score() {
return random.nextDouble() * 100;
}
}
You'd do better to create a proper object and store the values in that - this gives you two major benefits, 1) your code will be faster since you avoid needlessly recomputing double values and 2) your code will be clearer, since the fields will be named rather than making calls like details[0] where it's completely unclear what [0] is referring to.
Due to 2) I don't know what the fields are supposed to be, so obviously your class will look different, but the idea's the same:
public class PersonScore {
private double[] multipliers = new double[2];
private double[] summers = new double[3];
private String first;
private String last;
// expects a parsed CSV String
public PersonScore(String[] arr) {
if(arr.length != 7)
throw new InvalidArgumentException("Must pass exactly 7 fields");
multipliers[0] = Double.parseDouble(arr[0]);
multipliers[1] = Double.parseDouble(arr[1]);
summers[0] = Double.parseDouble(arr[2]);
summers[0] = Double.parseDouble(arr[3]);
summers[0] = Double.parseDouble(arr[6]);
first = arr[4];
last = arr[5];
}
public double score() {
double ret = 1;
for(double mult : multipliers)
ret *= mult;
for(double sum : summers)
ret += sum;
return ret;
}
public String toString() {
return first+" "+last+": "+score();
}
}
Notice there's an additional benefit, that the score method is now more robust. Your implementation above hard-coded the fields we wanted to use, but by parsing and storing the fields as structure content, we're able to implement a more readable, more scalable score calculation method.

Categories