Can someone explain the Recursion in this Code - java

I've done HTML but that is nothing like learning java now in my AP class. So I'm pretty much brand new to coding. Today we learned about recursion and I'm pretty sure I understood it when it comes to using it like in this video.
https://www.youtube.com/watch?v=fpuWkZs51aM
But we then had to use it in a different way. We needed to make a program called WordPlay that accept any words, one at a time, until the word "STOP" is input. When stop was put in it prints them back out in reverse order. Here's the code.
import java.util.Scanner;
public class HelloWorld
{
public static void main(String[] args)
{
System.out.println("Enter list of words, one per line");
System.out.println("Final word should be STOP");
wordList();
}
public static void wordList()
{
Scanner keyboard = new Scanner(System.in);
String word = keyboard.next();
if (word.equalsIgnoreCase("STOP"))
System.out.println();
else
wordList();
System.out.println(word);
}
}
So the part that I don't understand is that this works fine but when I look at the ending of wordList() it seems to me that it would just keep repeating the last word that was input. I don't get what I'm missing. Can someone explain the logic here?

The recursion does output the word that was input, however each call to wordList gets a new local variable named word (each word value is on "the stack"). If you mark it final, nothing will complain - because the word isn't modified after initialization. Also, you should probably extract the Scanner (each invocation creates a new local one of those too).
public static void wordList()
{
Scanner keyboard = new Scanner(System.in);
final String word = keyboard.next(); // <-- this is the current word.
if (word.equalsIgnoreCase("STOP"))
System.out.println();
else
wordList(); // <-- it's not STOP, recurse... which
// will get a new local word (and print it).
System.out.println(word); // <-- however, this is still current word.
}

The function will execute from top to bottom as usual, but if it enters the else block it will jump back up to the beginning like shown below. It will 'loop' exactly like this until word equals "STOP", then it'll enter the if block, print out a new line (System.out.println()) then SKIP the else block, print out word then exit the function. Brackets in the if-else statement will make this easier to see.
public static void wordList()
{
|->Scanner keyboard = new Scanner(System.in);
|
| String word = keyboard.next();
| if (word.equalsIgnoreCase("STOP")) {
| System.out.println();
| }
| else {
|---wordList();
}
System.out.println(word);
}

Its basically a recursion function or method which calls itself again and again until if condition inside it is false.
So here first new word entered by user is stored in variable called word, then if condition will check if value stored in word is Stop, if its not then again wordlist method is called and all above process is repeated again.
So each time new values entered is stored in word variable.
Thats all!!

public static int wordList()
{
Scanner keyboard = new Scanner(System.in);
String word = keyboard.next();
if (word.equalsIgnoreCase("STOP"))
{
System.out.println();
return 0;
}
System.out.println(word);
return wordList();
}
Try this

This will be the sequence of operations
1) call wordlist()
2) Get a word, say WORD1 and store in local variable word.
3) before calling wordlist recursively, WORD1 goes into stack. Stack is something like a box where you can fill say biscuits one over an other, and you can take out the biscuit that you placed last. Now the stack has WORD1
4) get another word, say WORD2 and store in local variable word. This is a new function call, even if it is recursive. So a new local variable word is allocated memory.
5) before calling wordlist recursively, WORD2 goes into stack. So now WORD2 will be the top one and WORD1 will be below in the stack.
5) get another work, now it is STOP.
6) STOP is printed
7) function returns
8) now the flow returns to previous call. Now WORD2 is popped out of stack as the local variable holding WORD2 belongs to this instance of the recursive call.
8) print WORD2 and return to previous call. Now WORD1 is popped out of the stack as the local variable holding WORD1 belongs to this instance of the recursive call
9) WORD1 printed.
Just to tell you an analogy, let us assume you have a similar task. You have to get a set of books from a friend standing besides you. You have to give him back the books in the reverse order as you got it from him as soon as he gives you a book named stop.
1) You get the book from him
2) before getting the next book, you keep it on a table, since you cannot hold this and get more books from your friend
3) yet get the next book from him
4) before getting the next book, you keep it over the first book
5) you continue doing this until you get a book named stop
6) now you start returning the books, first you will return the book named stop and as you continue, since the books are stacked, you will be returning the book in reverse order.
Hope this clarifies.

It would just repeat that last word entered if the line System.out.println(word) was before the if statement.
To understand recursion, you need the notion of the "stack". Each call to wordList() occurs in a separate level in the stack. There is a different word variable in each of these stack levels.
Since the ``System.out.println(word)` line happen after the recursive call, each of these are executed when un-piling the stack (i.e. after the previous level returns). That's why words appear in reverse order. Image: if you pile boxes one atop the other, when you un-pile them, the last box is the first to go out (hence the acronym LIFO=Last In First Out).
Another important concept for recursion is to have a way of stopping it (i.e. prevent infinite recursion). In this program, it is done when the user enters "STOP".

I like to think of these problems as a 'call stack'. Each time you 'call' the method recursively you add another 'stack'. Every recursive method needs a stopping case. In your problem the first occurrence of the word 'STOP' (how convenient) acts as your stopping case.
For example if someone enters:
"Fox"
"Bear"
"Deer"
"STOP"
As soon as the word "STOP" appears, it will be printed. Now we pick up where we left off in your 'call stack' which is the ending of
wordList()
Now the only step left is
System.out.println(word)
The word 'Deer' will be printed and now our list being printed is:
"STOP"
"Deer"
And so forth until we reach the last word.

Related

Need help reading through my String to push to Stack

Hello and thank you for reading. I have written a program to reverse the words in a string using a stack. I am to use 3 sentences and reverse each sentence separately. I have been able to reverse the entire string, which wasn't an issue. Then I changed my program so I am reading to the period and reversing the first sentence. However, I can't get it to read the next sentence. I believe I need a second loop but this is where I struggle. There are several questions/answers on this site that address this assignment, but none that have really taken the approach I have so they aren't relevant. At least, not from what I can tell. This is what I have:
for (String word : wordArray) {
if (word.endsWith(".") {
Stack.push(word.substring(0, word.length()-1));
break;
}
else {
Stack.push(word);
}
}
So my sentences are: "Cats are cool. Dogs are cool. So are turtles." My program will print:
"cool are Cats"
I know I need to append a period and I can figure that out later. I'm just struggling with how to create a second loop to continue reading the rest of the string.
What I need is: "cool are Cats. cool are Dogs. turtles are So."
You were thinking in the right direction: you do need one more loop to empty out the stack when the end of a sentence has been encountered, and you need some mean of storing the data (it could be an ArrayList, or a StringBuilder).
I would use a StringBuilder to store reversed sentences.
The logic of generating a reversed sentence by retrieving the elements from the stack can be extracted into a separate method. In a nutshell, it's while-loop that runs until the stack is not empty. To join the string back into a sentence, I would use a StringJoiner which facilitates combining the strings using a specified delimiter (feel free to reimplement this logic as you see fit, the point of this answer is to explain the algorithm and provide a source of inspiration rather than be a ready to go copy-past solution, for instance, you can use two StringJoiners instead of the combination StringJoiner + StringBuilder, I've only shown one possibility).
That's how it might be implemented:
public static String reverseSentences(String[] wordArray) {
Stack<String> stack = new Stack<>();
StringBuilder reversedSentences = new StringBuilder();
for (String word : wordArray) {
if (word.endsWith(".")) {
stack.push(word.substring(0, word.length() - 1));
reversedSentences
.append(createSentence(stack)) // appending the reversed sentence
.append(". "); // adding a period and a white space at the end of the sentence
} else {
stack.push(word);
}
}
return reversedSentences.toString();
}
public static String createSentence(Stack<String> stack) {
StringJoiner sentence = new StringJoiner(" "); // white space would be used a delimiter between the words
while (!stack.isEmpty()) {
sentence.add(stack.pop());
}
return sentence.toString();
}
main()
public static void main(String[] args) {
System.out.println(reverseSentences("Cats are cool. Dogs are cool. So are turtles.".split(" ")));
}
Output:
cool are Cats. cool are Dogs. turtles are So.
Before your loop, you need to create your stack like
Stack<String> wordStack = new Stack<String>();
You would do your current push operations on wordStack, and then you would pop in your second loop as you would expect.
You got very close.

How do I create a while loop in java that will end the game once the two user inputs match?

I have been trying to create a game that asks the user to type in 2 three-letter words; the program is supposed to give clues for how close the words match by splitting them up and stating if the letters come before, or after, each other in the alphabet.
The game is nearly done, but my problem shows up when I try to start a new turn after one guess. I need some kind of while loop, but I've rearranged blocks of the code so many times that I feel like it made the entire thing more convoluted. The prompt for the second user to answer a question, as well as the clue, should be repeated every time the two inputs don't fully match.
Example Output when the two user inputs are cat and fan: after, a, before
The "after" shows that the letter comes after the user's letter in the alphabet, and the "before" shows that the letter comes before the user's letter.
EDIT: I have taken the answers into account as much as I can, thank you so much. So far, I have implemented a do while loop and tried to fix my variables. In the end, I feel that I may have to create an object to be able to recopy the code of the user inputs after a certain conditional statement would be set to false.
My new issues are
1. The compiler cannot find the symbols x1,y1,z1,x2,y2, and z2 whenever I have the user inputs inside the do while loop.
2. If I tried to make a new object, I would be rewriting & rearranging more than what might be necessary.
This is still ongoing, and as I continue to work on it I will keep updating this post.
(EDITED CODE -- I saved the original code which I can send to anyone who would like to see it.)
import java.util.Scanner;
class Main{
public static void main(String[] args) {
System.out.println("Guess The Word\n(requires two players)");
System.out.println("If the letter in each word matches, the letter will be reprinted.");
System.out.println("If the letter guessed doesn't match, either \"before\" or \"after\" will print.");
Scanner in1=new Scanner(System.in);
//Scanner in2=new Scanner(System.in);
try{
boolean correct1=false; boolean correct2=false; boolean correct3=false;
int indication=0;
//asks for user input and stores in substrings
do{
System.out.print("First Player, enter a three letter word: ");
String user1=in1.nextLine();
String x1=user1.substring(0,1);
String y1=user1.substring(1,2);
String z1=user1.substring(2,3);
System.out.print("Second Player, enter a three letter word: ");
String user2=in1.nextLine();
String x2=user2.substring(0,1);
String y2=user2.substring(1,2);
String z2=user2.substring(2,3);
}
while(!correct1||!correct2||!correct3);
//possible end to loop
// if(user1==user2){indication=1;}
// else{indication=0;}
//comparisons of each letter
int comp;
int comp2;
int comp3;
comp=x1.compareTo(x2);
comp2=y1.compareTo(y2);
comp3=z1.compareTo(z2);
//while1=(comp!=0);
//while2=(comp2!=0);
//while3=(comp3!=0);
//if statement 1
if(comp==0){
System.out.print(x1);
correct1=true;
}
else{
// System.out.println(comp);
if(comp>0){
System.out.println("before, ");
}
else{
System.out.print("after, ");
}
}
//if statement 2
if(comp2==0){
System.out.print(y1);
correct2=true;
}
else{
// System.out.println(comp);
if(comp2>0){
System.out.println(", before, ");
}
else{
System.out.print(", after, ");
}
}
//if statement 3
if(comp3==0){
System.out.print(z1);
correct3=true;
}
else{
// System.out.println(comp3);
if(comp3>0){
System.out.println(", before");
}
else{
System.out.print(", after");
}
}
//ignore else{System.out.print("Congratulations!");}
}
finally{in1.close();}/* in2.close();}*/
}
}
Maybe declare 3 booleans (1IsCorrect, 2IsCorrect, 3IsCorrect) set them default to false and in the if(comp/comp1/comp2 == 0) statements after printing the value set the corresponding boolean to true.
then put it in a do while(!1IsCorrect || !2IsCorrect || !3IsCorrect)
declare a variable perhaps for isFirstRun before loop and instantiate it to true at the declaration, then set to false at the very end.
Make an if !isFirstRun statement and add in the code there to ask for the next guess
Hope this works

Using scanner.next() outside loop yields weird results

Recently a friend of mine showed me her code seeking my advice on why it wouldn't work. Her original code was this:
public static void printStem(String word) ...
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
System.out.println("Please enter the words: ");
String word = keyboard.next();
printStem(word);
while (keyboard.hasNext())
{
printStem(word);
word = keybord.next();
}
}
This will yield really weird results. It will ask the user twice, then executes printStem twice (which might be expected), and after that goes ahead and always prints only the first entered corpus (word).
Eventually I figured out that it would work as expected when removing the keyboard.next() from outside the loop like so
public static void printStem(String word) ...
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
System.out.println("Please enter the words: ");
while (keyboard.hasNext())
{
String word = keybord.next();
printStem(word);
}
}
When asked why this would be I had no plausible explanation, as this should behave identical. My best guess is that something must be smelly with hasNext() but I couldn't figure out why exactly. So. What is going on here? Any explanation is appreciated :)
Some explanation about hasNext():
Returns true if this scanner has another token in its input.
This method may block while waiting for input to scan.
The scanner does not advance past any input.
In your first piece of code
you scan for a word: String word = keyboard.next();
You print it: printStem(word);
You enter into a while loop which waits until you give some input: keyboard.hasNext()
In step 3 you take the input but never store it in String word and you print it. Naturally previous value of word will be printed.
Then you do a next read by next().
Explanation for next():
Finds and returns the next complete token from this scanner. A complete token is preceded and followed by input that matches the delimiter pattern. This method may block while waiting for input to scan, even if a previous invocation of hasNext() returned true.
Hence you get a weird behavior.
This will yield really weird results
Yeah, because the logic is wrong.
You get the input
String word = keyboard.next();
print it
printStem(word);
then print it again, and ask for another word:
while (keyboard.hasNext())
{
printStem(word);
word = keybord.next();
}
So every time you loop you print the word they entered last time, rather than the word they entered this time. You just need to swap the two lines in the while-loop, which then makes the keyboard.next() and printStem(word) outside of the loop body redundant.
as this should behave identical
No it shouldn't. You reversed the order of operations in the while-loop body.

How to return last letter in ArrayList and return total number of letters entered?

I have been trying to do a question as follows:
The program should keep prompting the user to enter a letter until the user types ‘!’, which ends the program. Each time the use enters a letter, the program should add the letter to the previous letters entered and print the result. The program should also return:
the last entered letter when ‘#’ is entered.
the total number of letters entered when ‘#’ is entered.
I am stuck on how to return the last entered letter and returning number of letters entered. I thought about if statements but they don't seem to be working. Here is my code so far:
import java.util.Scanner;
import java.util.ArrayList;
public class check {
static Scanner input = new Scanner (System.in);
static ArrayList<String> array= new ArrayList<>();
public static void main(String[] args) {
System.out.print("Please enter a letter: ");
String a=input.nextLine();
while ( !a.equals("!")) {
array.add(a);
for(String b : array) {
System.out.print(b);
}
System.out.print("\n"+"Please enter a letter: ");
a=input.nextLine();
}
// array.add(a);
if((a.equals("#"))) {
ArrayList.get(ArrayList.size()-1);
for(String b : array) {
System.out.print(b);
}
}
I know the if statement I have done is incorrect because it's giving red line under. But don't know how and what to do next.
Here's what your code does line by line:
while ! is not the key that is pressed, add the key that was pressed to an ArrayList of Strings called "array." After that, print out every string in "array," and then wait for the next keypress.
If ! is pressed, the while loop doesn't occur (nothing is added to the array, nothing is printed out, there is no .nextLine()).
At this point, if that last key wasn't "#," do nothing and the program terminates. If it was, make a static call to
ArrayList.get() //(this is a compilation error)
then make a static call to
ArrayList.size() - 1 //(another compilation error).
To fix these errors and clean the code up to make it readable, it should be written as:
if(a.equals("#")){ //Remove the superfluous parentheses
array.get(array.size() - 1);
When you change that line, you will now be doing this: if that last key was "#," get the last string in the array and do nothing with it (I assume you want a System.out.println() here, as doing a array.get(array.size() - 1) but not assigning it to a variable does nothing). After doing essentially nothing, take every string in array and print it out.
The problems should be apparent if you talk out what you're code is doing like this; it can really help! You will have to change the program a bit to accomplish what you want as well.
In my opinion what you want to do is a while loop that checks !a.equals("!") because we still want ! to end the program. However, in the while loop you need add an if and an else if after you print out the values in the array: the if checks to see if the key entered was a "#" and if it is, print a... the else if checks to see if the key was "#" and if it is print array.size().
That's IF you're reading the requirements for the assignment right too; it could be that you're supposed to be doing string concatenation instead of populating an ArrayList, i.e., declare stringBuilder outside while block, and inside while block:
if (stringBuilder == null){
stringBuilder = new StringBuilder(a);
}
stringBuilder.append(a);
//print stringBuilder and then print a or stringBuilder.length()

push() etc in an ArrayStack

For my assignment I've had to create an ArrayStack, a StackADT, and now I have to make a program to take in a string and output it in reverse.
Now this sounds simple, but I have no idea how to push something into the array. I've been googling the shit out of this and can't find an actual answer that makes sense.
Specifically I'm having trouble linking the main program to the actual array, and then linking the input string to the push().
public class ReverseSentenceMain {
public static void main (String[] args)
{
AssignmentArrayStack stack = new AssignmentArrayStack();
//private AssignmentArrayStack<String> stack;
public ReverseSentenceMain()
{
stack = new AssignmentArrayStack<Integer>();
}
String sentence;
String result = null;
String words;
stack = (T[])(new Object[initialCapacity]);
Scanner in = new Scanner(System.in);
System.out.println("Enter a sentence");
}
}
I'd appreciate any help and thanks for your time
You start scanning by calling next on the scanner.
sentence = in.next();
Then you perform a split on whitespace to divide up the sentence into tokens that you push into your stack. The scanner can do the split for you I think. Look at the Scanner JavaDoc or String JavaDoc for more information.
You should format the code. Press ctrl+K or use the little 101010 icon.
Anyways. The stack class should have a push method. You need to get the sentence. You could loop through the sentence and then push the characters onto a stack. Once you do that, then you can pop the characters off to print the string in reverse order.
loop through string
stack.push(string[i])
while(currChar = stack.pop())
print currChar (or store to another variable)
I believe that will work. Been a while since ive done anything in java.
A stack isn't really an array. Its more like a linked list. It adds an element as the first element in a linked list and then updates the pointer.
Acutally heres a decent example http://www.javacoffeebreak.com/faq/faq0037.html
And i just noticed you want to reverse the sentence and not the word, so do what willcodejavaforfood said and tokenize it with scanner. I remember you can do this. It will read up every whitespace. you get that token and add it to the stack. Some kind of type of concept though.

Categories