How to write a reverse line program with recursion? - java

I'm learning recursion and am having problems writing a 'simple' program. Help would be appreciated. Thanks!The code compiles with no syntax erros but i still cant use it to serve its purpose.
my updated code:
import java.io.*;
import java.util.*;
class recursion1
{
static Scanner inFile = null;
public static void main(String[] args) throws IOException
{
try
{
inFile = new Scanner(new File(args[0]));
}
catch (IOException e)
{
System.out.println("File may not exist");
}
reverse(inFile);
inFile.close();
}
public static void reverse(File inFile) throws IOException
{
String line = inFile.nextLine();
if (inFile.hasNextLine())
{
reverse(inFile);
}
System.out.println(line);
}
}

I'm confused as to the purpose of the counter. You decrement it, but you never evaluate it for any sort of logical comparison. I don't think it is unneccessary, you just need to utilize it in a comparison that is used to break the recursive loop. Recursion requires a part that makes a call to the recursive function, and another part that breaks the cycle and begins the process of backing out of the recursive calls.

Here is how to write a reversing program in general. I'm not giving you Java, I'm giving you "pseudocode".
function print_reverse(file)
local_variable line
line = read_from(file)
if (we are not at end of file)
print_reverse(file)
print line
Because line is a local variable, you get a new instance of it on each call to print_reverse(). When you read in the whole file, and you want to print the lines in reverse, the lines need to be stored somewhere. In this recursive function, the lines are stored one at a time, one in each call to print_reverse().
I like to think of recursive functions as "winding" further and further until they hit a limit, then "unwinding" as they come back out. The limit is called the "basis case". With any recursive function you need to have a clear idea of what your basis case is. For print_reverse(), the basis case is hitting the end of file on the input file.
After print_reverse() hits its basis case, it stops calling itself recursively; it prints a line and then unwinds. As each recursive call ends, it returns to the previous recursive call, which then in turn prints its line and unwinds again. This continues until the first call prints its line and terminates, at which point the recursion is finished and all lines have been printed.
So, to summarize: when "winding" we read a line and save it, the basis case is end of input, and when "unwinding" we print a saved line. Since unwinding occurs in the exact opposite order of winding, the lines print in reversed order.
If the input file is very large, this recursive solution may use up all the available stack space, in which case the program will crash. If you wanted to write a file-reversing program that could handle input files of any size, recursion is not going to work. However, look at how clean and simple this program is. Some problems are easier to code and understand if you use a recursive solution.
Reversing a file is pretty easy to do iteratively; just use a loop to read each line from the file and keep appending lines to some sort of list, then loop over the list in reverse printing lines. But other programs are elegantly simple when you write them recursively, and much harder if you don't. For example, the "Towers of Hanoi" puzzle has a very clean recursive solution.
http://www.mathcs.emory.edu/~cheung/Courses/170/Syllabus/13/hanoi.html

Related

Java - Scanner: does hasNext() changes accordingly after setting useDelimiter()?

Code:
Scanner input;
File file = new File("Latex3.bib");
input = new Scanner(file);
input.useDelimiter("#ARTICLE");
while(input.hasNext()) {
System.out.println("It should not print this");
s = input.next();
System.out.println("Token"+c+": "+s);
c++;
author = s.substring
(s.indexOf("author={")+8,
s.indexOf("}", s.indexOf("author={")+8));
System.out.println("Authors for this ARTICLE: "+author);
System.out.println();
}
(in the code, c is an int that I declared earlier in the original code for just counting and increasing by each loop).
I was getting weird exception from the code that I think it should not throw. After testing each input files, it turns out my while loop runs even when there's no "#ARTICLE" in the Latex3.bib file.
As far as I know, if the file does not have "#ARTICLE", that means that input does not get any token. So from the beginning, its hasNext() should return false. But it just wasn't.
The part what I think funny and strange is: if Latex3.bib is completely empty(not even one space bar or enter), the while loop or whatever reads it as an empty file, therefore no token is given to input.
However, if Latex3.bib has like 1~3 linebreak(enters), then that while loop runs. I have no idea why this is happening. I am suspecting that Scanner.useDelimiter(pattern) does not affect or at least cooperate perfectly with other Scanner methods like hasNext(), although I believe this won't be the real case because it's a very crucial functionality.
edit:
Just to be clear what exception I got, the StringIndexOutOfBoundsException was thrown at the point of assigning author(String). Well it's obvious because the file was empty... and there was nothing to substring or find index..

Java - Trying to create an arraylist of strings but the arraylist gets full(?)

I might just be doing something stupid here but I'm trying to write a program that will take all the text from an xml file, put it in an arraylist as strings, then find certain recurring strings and count them. It basically works, but for some reason it won't go through the entire xml file. It's a pretty large file with over 15000 lines (ideally I'd like it to be able to hand any amount of lines though). I did a test to output everything it was putting in the arraylist to a .txt file and eventually the last line simply says "no", and there's still much more text/lines to go through.
This is the code I'm using to make the arraylist (lines is the amount of lines in the file):
// make array of strings
for (int i=0; i<lines; i++) {
strList.add(fin2.next());
}
fin2.close();
Then I'm searching for the desired strings with:
// find strings
for (String string : strList) {
if(string.matches(identifier)){
count++;
}
}
System.out.println(count);
fout.println(count);
It basically works (the printwriter and scanners work, line count works, etc) except the arraylist won't take all the text from the .xml file, so of course the count at the end is inaccurate. Is arraylist not the best solution for this problem?
This is a BAD practice to do. Each time you put a string into an ArrayList and keep it there, you're going to have an increase in memory usage. The bigger the file, the more memory is used up to the point where you're wondering why your application is using 75% of your memory.
You don't need to store the lines into an ArrayList in order to see if they match. You can simply just read the line and compare it to whatever text you're comparing it to.
Here would be your code modified:
String nextString = "";
while (fin2.hasNext()) {
nextString = fin2.next();
if (nextString.matches(identifier) || nextString.matches(identifier2)) {
count++;
}
}
fin2.close();
System.out.pritnln(count);
Eliminates looping through everything twice, saves you a ton of memory, and gives you accurate results. Also I'm not sure if you're meaning to read the entire line, or you have some sort of token. If you want to read the entire line, change hasNext to hasNextLine and next to nextLine
Edit: Modified the code to show what it would look like looking for multiple strings.
Have you tried to use map, like HashMap. Since Your goal is to find the occurrence of word from a xml, hashmap will make your like easier.
The problem is not with your ArrayList but with your for loop. What's happening is that you're using the number of lines in your file as your sentinel value, but rather than incrementing i by 1 every line, you are doing it every word. Therefore, not all the words are added to your ArrayList because your loop terminates earlier than expected. Hope this helps!
EDIT: I don't know what object you are using right now to collect the contents of this xml file, but I would suggest using Scanner instead (passing the File as a parameter in the constructor) and replacing the current for loop with a while loop that uses while (nameOfScanner.hasNextLine())

Curious why this recursive code won't work, and exhibits really anamolous behavior in another method

New programmer here, having some problems with some code about what I would think is recursion.
public static int sum (int a) {
int input = goodInput(); //get input from below method without having to put its code in this one
if (input==-1)//so user has the ability to exit at any time
return a; //when user has finally entered -1, the final sum is sent out
else; //for scenarios before last input
int b = a + input; //adding the newest input to the sum
int c = sum(b); //throw the total into the method again until -1 is read
return c; //once -1 is read, a in that iteration is sent up through every iteration of the method until the original method gets its return
}
public static int goodInput () { //code to get input of correct type
Scanner input = new Scanner (System.in);
while (!input.hasNextInt()) { //if I put in integer input, the loop should not be entered, but this isn't happening
System.out.println("Integers only please");
input.next();
}
int finalInput = input.nextInt(); //Finally set good input
input.close(); //close scanner
return finalInput;
}
First method here is clearly just a way to get a sum. I know there are multitudes of other ways to just sum some numbers together, I've done a few myself, but when my class had its lesson on methods and wrote it up having something like the code I listed was the first thing I could think of as a solution, rather than what the teacher ended up recommending. Thought it would be a good learning exercise, in any case.
This code doesn't show any errors in eclipse, so I am stumped as to why it refuses to work. Indeed, it produces results I am really curious of; it naturally asks input at the beginning of the program, but when I enter 0, 1, or any other int, despite the scanner actually having an integer, "Integers only please" is printed, followed by Java announcing exceptions at the end of the while loop, at goodInput's calling in sum, at the return of c, and at the execution of sum in the main method, as well as at java.util.NoSuchElementException, java.util.Scanner.throwFor, and at java.util.Scanner.next.
I have very little idea what is happening here; my best guess would be memory issues, but bugs start occuring at the very first occasion! And the code in goodInput works perfectly well when just used as the main method; not sure why it being called by sum would cause problems.
Again, I don't just want some sum method. I just want to know why the code is behaving in this manner, and how an implementation of sum with my approach would actually work.
Not recursion is the problem here, but your Scanner. I have to admit that I am not too familiar with the Scanner class, but it seems that if you call input.close() and then reenter goodInput later, your System.in is closed. At least, stepping through with the debugger, I found that the line "Integers only please", is printed in the second invocation of goodInput. Deleting the line input.close(); did the trick for me, and your method worked as intended.
I'd suggest you initialize your scanner in the main method, pass it as an argument, and close it in the main method afterwards.
Edit:
The close method of the Scanner states the following:
If this
scanner has not yet been closed then if its underlying
java.lang.Readable readable also implements the java.io.Closeable
interface then the readable's close method will be invoked.
So, the underlying reader, i.e., System.in, was closed when you called close on the Scanner.

External files Java

So I'm having a bit of difficulty with this program I was assigned. Here is the prompt:
You are to read an external file of random integer values until the end of file is found. As you read the file you should determine how many numbers are less than the value 500 and how many numbers are greater than or equal to 500.
I have the data, and I know exactly how many numbers are supposed to be less than 500 and how many are greater than or equal to 500. The problem is that I don't know how to make the loop read until the end of the file is found, or how to print out the different lines to meet the conditions using if statements.
Here is my code:
import java.io.*;
import java.util.*;
public class Prog209a
{
public static void main(String[] args) throws IOException
{
Scanner sf = new Scanner(new File( "C:\\Users\\Air\\Documents\\java \\Prog2220.in"));
int maxIndx = -1;
String text[] = new String[1000];
while(sf.hasNext()==true)
{
maxIndx++;
sf.close();
}
}
I'm not asking someone to write the code for me, but to help give me a place to start or some hint. I'm not really good at reading external files, but I'm trying to learn. Feedback is appreciated. Thanks!
Your Scanner instance will currently continue reading the file until it no longer has any lines to read. The only drawback is that you're not reading any lines.
Use Scanner#nextLine(), or any of its "cousins", to suit your needs in your program.
In extension to Makoto's answer, your strategy should be:
Initialize three variables: currentNum, greaterThan, lessThan to zero.
Start scanning file line by line. Parse each line and store the parsed value in currentNum.
Test if currentNum is less than 500. If yes, then increment lessThan, otherwise decrement greaterThan.
Keep doing this till you reach EOF.
Done.

How to read each lines of the input and output them in sorted order?

Duplicate lines should be printed the same number of times they occur in the input. Special care needs to be taken so that a file with a lot of duplicate lines does not use more memory than what is required for the number of unique lines.
I've tried all the collection interfaces but none seems to be working for this question :(
Can someone please help me??
Thanks.
The code below is memory inefficient, as it stores duplicate lines in the PriorityQueue. Hope this helps
public static void doIt(BufferedReader r, PrintWriter w) throws IOException {
PriorityQueue<String> s=new PriorityQueue<String>();
String line;
int n=0;
while ((line = r.readLine()) != null) {
s.add(line);
n++;
while (n!=0) {
w.println(s.remove());
n--;
}
}
The ideal approach would be to use a sorted multiset, such as Guava's TreeMultiset.
If you're not allowed to use external libraries, you can replace s.add(line) with s.add(line.intern()). This tells the JVM to put a copy of each unique line into the String pool and share the same object among all the references.
Note that putting Strings into the pool may cause them to stick around for a long time, which can cause problems in long-running applications, so you don't want to do this casually in a production application, but for your homework problem it's fine. In the case of a production application, you'd want to put the Strings into a SortedMap where the value is the count of times the line appeared, but this is more complicated to code correctly.
You are looking for Insertion sort, which is an online algorithm, assuming lines are being inputted on the fly, if its an offline case(text file which isn't being modified on the fly), well you can use any sort algorithm, thinking of each line as a String, and the complete file as an Array of strings. Sort the array, then loop through it while printing, and then you got, sorted lines printed.

Categories

Resources