Recursion and LinkedList in Java - java

Ok so say I have a function that looks for a specific word in a custom LinkedList class:
public LinkedList find(String word) {
if (this.word.equals(word))
return this;
if (next==null)
return null;
if (next.find(word)==next)
return next;
return null;
}
This code works fine, however it returns the FIRST found object that matches the criteria. What if I wanted to return the LAST object found that matches the paramater? I'm having a hard time figuring this out. Keep in mind I want to use recursion.
EDIT: What would be wrong with this code:
public LinkedList findLast(String word) {
LinkedList temp=new LinkedList(word, null);
if (next==null && next.word.equals(word))
return next;
if (next==null && !next.word.equals(word))
temp=next.findLast(word);
return temp;
}

Well, think of it this way: you need to recurse right to the end of the list, and then let the return value bubble up.
So the start of your method should either be a recursive call to look further down the list, or noting that we're at the end of the list - which is equivalent to the "further" result being null.
Now when you're returning, there are three options:
You've already found a match later than the current point - so return that reference
You've not found a match (so the return value of the recursive call was null) and:
The current point's word matches - so return the current point
The current point doesn't match - so return null
Hopefully that should be enough to get you to an implementation - if not, please ask more questions. I'd rather not give a full implementation when this is presumably homework.

Store a reference to the latest one found and keep on calling itself until it returns null -- then return the latest-reference.
Note, for clarification: you're going to have to iterate through your entire linked-list (unless you have a doubly-linked-list) to achieve this -- store a reference every time you find a match (but just overwrite the same reference each time) -- then return whatever the reference holds once you reach the end of this list.
public class LinkedList {
private static int uniqueIdCounter = 0;
private final String word;
private int uniqueId;
private LinkedList next = null;
public LinkedList( String word ) {
this.word = word;
this.uniqueId = uniqueIdCounter++;
}
#Override
public String toString() {
return this.word + "(" + this.uniqueId + ")";
}
public void setNext( LinkedList next ) {
this.next = next;
}
public LinkedList find( String word ) {
return this.find( word, null );
}
public LinkedList find( String word, LinkedList result ) {
if( this.word.equals( word ) ) {
result = this;
}
if( this.next != null ) {
result = this.next.find(word, result);
}
return result;
}
public static void main(String[] args) {
LinkedList head = new LinkedList( "A");
System.out.println( "Head is: " + head );
LinkedList B = new LinkedList( "B" );
head.setNext( B );
System.out.println( "B is: " + B );
LinkedList A2 = new LinkedList( "A" );
B.setNext( A2 );
System.out.println( "A2 is: " + A2 );
LinkedList last = head.find( "A" );
System.out.println( "Last is: " + last );
}
}
And here's the output:
Head is: A(0)
B is: B(1)
A2 is: A(2)
Last is: A(2)

Every straight recursive function has two places for some useful actions: before further method call and after:
function(n){
doBefore(n);
function(n+1)
doAfter(n)
}
doBefore() is executed "on the way forward", doAfter() is executed "on the way back". Now your algorithm checks word equality on the way forward. You have to modify your algorithm so that this check is performed on the way back.

public LinkedList find(String word, LinkedList result) {
if (this.word.equals(word))
result = this;
if (next != null )
return next.find(word, result)
return result;
Two-liner:
public LinkedList find(String word, LinkedList result) {
result = this.word.equals(word) ? this : result;
return next == null ? result : next.find(word, result);
#fprime: Ya, explanation: remember the result, replace it with later result, return when at the end.
Method with one argument:
public LinkedList find(String word){
result = this.word.equals(word) ? this : null;
if(next != null)
previous = next.find(word);
return (previous != null) ? previous : result
else
return result;

Just run it backwards from the tail.
public LinkedList find(String word) {
if (this.word.equals(word))
return this;
if (prev==null)
return null;
if (prev.find(word)==prev)
return prev;
return null;
}

To start with, you initial find(String word) does not work correctly.
Your first if statement is perfect. It is you success base case.
Your second if statement is also perfect. It is your failure base case.
Your third is where you go off the rails. You have handled all (in this case both) base cases, now all that is left is the recursive case. You don't need to check anything here. next.find(word) will return the correct answer, success or fail.
For findLast(String word), I can't add much to what Jon Skeet said. About the only advice I can add it to never have the a node check its neighbor. Each node should only ever check itself. You should see plenty of this.word.equals(word) but never next.word.equals(word).

public LinkedList find(String word) {
if(this.word.equals(word)) return this;
return next==null?null:next.find(word);
}
public LinkedList rfind(String word) {
if(next != null) {
LinkedList res = next.rfind(word);
if(res != null) return res;
}
return this.word.equals(word)?this:null;
}

Related

toString method for a doubly linked list using recursion

public String recursiveToString()
{
DoubleLinkedListNode<T> current = first;
String list = "";
if(current == null)
{
return "";
}
else
{
list += current.info + ", ";
current = current.next;
return list + recursiveToString();
}
}
It is supposed to print out the list when I run the code but it just crashes every time it runs. This is everything that I've tried to do so far.
First off you'll want to pass the current position in the list back into the function each time, so change your signature to this:
public String recursiveToString(DoubleLinkedListNode<T> current)
Then alter your code a bit so it uses that and continues to pass it down, the list variable is also unnecessary, the recursion will take care of concatenating everything:
public String recursiveToString(DoubleLinkedListNode<T> current)
{
if(current == null)
{
return "";
}
else
{
return current.info + " " + recursiveToString(current.next);
}
}
If you would like to do it without changing the signature of the function, just rename the function I have above and create the definition for your parameterless function like so:
public String recursiveToString()
{
return aboveFunction(first);
}

Recursive tree encryption method using dfs

This problem is not for an assignment, although it's a somewhat typical "assignment-like" problem that I'm trying to solve in a different way.
I want to write a method that will recursively go through a binary tree using a depth-first search algorithm to find a match for a character. Once it finds the matching character, I want it to return a string that maps the position of the character in the tree using 0s and 1s. "001",for example, would indicate that the character is found by going to the left node of the root node, the left node of that node, and then to the right node of that node.
Here is the code I have so far:
private static String encryptSearch(char c, BinaryNode curNode, String result)
{
char data = (char) curNode.getData();
if (data != c)
{
if (curNode.hasLeftChild())
{
result = result + "0";
encryptSearch(c, curNode.getLeftChild(), result);
}
if (curNode.hasRightChild())
{
result = result + "1";
encryptSearch(c, curNode.getRightChild(), result);
}
result = result.substring(0, result.length()-1);
}
return result;
}
The method is initially sent the character to be searched for, the root node, and null for the result. This method returns nothing except 0s. I think there are multiple problems with my code, but the largest one is that when the search reaches a leaf node, it returns. I've been unable to think of a way around this problem while still returning a string. I could easily write a void method that acts on the result string as an external variable, but I don't want to do that for the purpose of the exercise. Any help is appreciated!
Use the mutable StringBuilder instead of String. Also there should be a way to know that you got the result from left one (if any) before searching right one. So I suggest following changes.
private static boolean encryptSearch(char c, BinaryNode curNode, StringBuilder result) {
char data = curNode.getData();
if (data != c) {
boolean found = false;
if (curNode.hasLeftChild()) {
found = encryptSearch(c, curNode.getLeftChild(), result);
if (found) {
result.insert(0, "0");
return true;
}
}
if (curNode.hasRightChild()) {
found = encryptSearch(c, curNode.getRightChild(), result);
if (found) {
result.insert(0, "1");
return true;
}
}
return false; //no result
}
return true;
}

recursive toString in Queue Linked List in Java

I need to implement a toString() recursive method for a linked list Queue. I know my toString method worked fine on a linked list implementation I did last week, so something is wrong with how I'm handling the Queue aspect of it.
toString method for my QueueList:
public String toString()
{
if (front.info == null)
{
System.out.println("Error, queue is empty");
return "";
}
if (front.link == null) //base case: if this is last element in stack
{
return (" \"" + front.info + "\" , ");
}
else //normal recursive function
{
return (" \"" + front.info + "\" , " + front.link.toString());
}
}
and my constructors and such for QueueList:
public class QueueNode
{
E info;
QueueNode link;
}
private QueueNode front;//first element to be placed into queue
private QueueNode rear;//last element to be placed into queue
private int NoE;//counter for number of elements in queue
public QueueList()
{
front = null;
rear = null;
NoE = 0;
}
I tried to see what was going on in it using this test:
public boolean test() {
QueueList<String> q = new QueueList<String>();
q.enqueue("The Godfather");
q.enqueue("Casino");
q.enqueue("Goodfellas");
String r = q.toString();
q.PrettyPrint();
with the output
IN -> [ "The Godfather" , QueueList$QueueNode#a3901c6] -> OUT.
I realize this is because I'm telling saying front.link.toString() in the recursive part of the toString method, but even if I change it to front.link.info.toString(), my output is
IN -> [ "The Godfather" , Casino] -> OUT.
It may be possibly something to do with with my enqueue and dequeue methods then, which are as follows:
public void enqueue(E element)
{
QueueNode newNode = new QueueNode();//creates new Node to hold element
newNode.info = element;//set info of new Node to element
newNode.link = null;//make link null since it's at back of list
if (rear == null)//checks if queue is empty
{
front = newNode;
}
else
{
rear.link = newNode;//sets second to last node's link to newNode
}
rear = newNode;//makes newNode the new last link
NoE++;//increase counter
}
public E dequeue() throws InvalidOperationException
{
if (front == null)//sanitize code
{
throw new InvalidOperationException("There is nothing in the queue.");
}
E element = front.info;//creates an element file that takes the info in front of queue
front = front.link;//makes second-to-front element new front
if (front == null)//if this emptied the queue, make sure rear is also empty
{
rear = null;
}
NoE--;//reduce counter
return element;
}
Please help me out if you can. Thanks.
There is absolutely no need to make toString recursive, and in fact it is incorrect to do so. Your data structure is not recursive (i.e. a tree) but linear.
If your list contained, say, 1 million items, you would quickly run out of stack space (StackOverflow, literally).
Use a loop instead.
EDIT: If you are required do to this recursively, then the issue is that the recursive method must be QueueNode#toStringRecursive(), not Queue#toString(). The method Queue#toString() allocates a buffer and provides it to a special toStringRecursive() method on QueueNode which does the recursion. QueueNode#toString() must be responsible only for its own node contents.
Method Queue#toString()
public String toString()
{
StringBuilder buf = new StringBuilder();
if (front == null)
// queue is empty
else
front.toStringRecursive(buf);
return buf.toString();
}
Method QueueNode#toStringRecursive()
public void toStringRecursive(StringBuilder buf)
{
buf.append(this.toString());
if (this.link != null)
this.toStringRecursive(buf);
}
where QueueNode.toString() is responsible only for stringifying one node (itself).
Note that this is one way to do it. It would be possible to write this as a recursive method on Queue as well, but it could not be called toString(). Queue#toString() would set up the initial conditions and then invoke the recursion.

Print Tree components

I am new to java and I want to create a very simple "word completion " program. I will be reading in a dictionary file and recursively adding the words into a Node array (size 26). I believe I have managed to do this successfully but I am not sure how to go through and print the matches. For the sake of testing, I am simply inserting 2 words at the moment by calling the function. Once everything is working, I will add the method to read the file in and remove junk from the word.
For example: If the words "test" and "tester" are inside the tree and the user enters "tes", it should display "test" and "tester".
If somebody could please tell me how to go through and print the matches (if any), I would really appreciate it. Full code is below.
Thank you
What you implemented is called "trie". You might want to look at the existing implementations.
What you used to store child nodes is called a hash table and you might want to use a standard implementations and avoid implementing it yourself unless you have very-very specific reasons to do that. Your implementation has some limitations (character range, for example).
I think, your code has a bug in method has:
...
else if (letter[val].flag==true || word.length()==1) {
return true;
}
If that method is intended to return true if there are strings starting with word then it shouldn't check flag. If it must return true if there is an exact match only, it shouldn't check word.length().
And, finally, addressing your question: not the optimal, but the simplest solution would be to make a method, which takes a string and returns a node matching that string and a method that composes all the words from a node. Something like this (not tested):
class Tree {
...
public List<String> matches(CharSequence prefix) {
List<String> result = new ArrayList<>();
if(r != null) {
Node n = r._match(prefix, 0);
if(n != null) {
StringBuilder p = new StringBuilder();
p.append(prefix);
n._addWords(p, result);
}
}
return result;
}
}
class Node {
...
protected Node _match(CharSequence prefix, int index) {
assert index <= prefix.length();
if(index == prefix.length()) {
return this;
}
int val = prefix.charAt(index) - 'a';
assert val >= 0 && val < letter.length;
if (letter[val] != null) {
return letter[val].match(prefix, index+1);
}
return null;
}
protected void _addWords(StringBuilder prefix, List<String> result) {
if(this.flag) {
result.add(prefix.toString());
}
for(int i = 0; i<letter.length; i++) {
if(letter[i] != null) {
prefix.append((char)(i + 'a'));
letter[i]._addWords(prefix, result);
prefix.delete(prefix.length() - 1, prefix.length());
}
}
}
}
Maybe a longshot here, but why don't you try regexes here? As far as i understand you want to match words to a list of words:
List<String> getMatches(List<String> list, String regex) {
Pattern p = Pattern.compile(regex);
ArrayList<String> matches = new ArrayList<String>();
for (String s:list) {
if (p.matcher(s).matches()) {
matches.add(s);
}
}
return matches
}

Recursive method returning a string at each step?

I have a slight algorithmic problem. I think I miss something but can't exactly figure out what.
I want to walk to a tree containing strings and get out with a unique string.
Here is a graphical example of a tree I would like to parse.
My trees would have three different types of elements :
Boolean operators (OR, NOT, AND) => BE
other operators (like the =) => QO
leaves (last elements) =>LEAF
I would like to end up with something like this :
"LEAF QO LEAF BE LEAF QO LEAF "
For now, I use a recursive method: I check the current element of the tree, and re run the method on its children depending on the type of elements I have. For each step I would populate my final string.
public class SingleTest {
static String[] booleanElements = {"or", "and", "not"};
public static void main(String[] args) throws Exception {
CommonTree tree = (CommonTree)parser.parse().getTree();
if(true){
String where = "";
printWhere(tree, where);
System.out.println(where);
}
}
/*
* Print to where tests
*/
public static boolean isBooleanElement(CommonTree t){
return Arrays.asList(booleanElements).contains(t.toString().toLowerCase());
}
public static String printWhere(CommonTree t, String where){
//---------------------
// Checking node type
//---------------------
// Boolean Element
if (isBooleanElement(t)){
// Continue parsing the tree
for ( int i = 0; i < t.getChildCount(); i++ ) {
printWhere((CommonTree)t.getChild(i), where+ "BE");
}
}
// Last element of tree (LEAF)
else if(t.getChildCount() == 0 ){
where = where + "LEAF";
}
// query operator
else{
// Continue parsing the tree
for ( int i = 0; i < t.getChildCount(); i++ ) {
printWhere((CommonTree)t.getChild(i), where + "QO");
}
}
//---------------------
return where;
}
My problem is that this code :
String where = "";
System.out.println(printWhere(tree, where));
returns "" (Which is logical due to my implementation).
So my question is, how can I get to have a non void string as final output ?
Hope this is clear enough
Thank you for your help
Please note that this class is used for test purpose only, and I know that putting static everywhere is bad practice :)
EDIT :
The problem was (as expected) due to my lack of experience with recursion.
Here is my final code :
public static String printWhere(CommonTree t, String where){
//---------------------
// Checking node type
//---------------------
// Boolean Element
if (isBooleanElement(t)){
// Continue parsing the tree
for ( int i = 0; i < t.getChildCount(); i++ ) {
where = printWhere((CommonTree)t.getChild(i), where) + "BE";
}
}
// Last element of tree (LEAF)
else if(t.getChildCount() == 0 ){
where = where + "LEAF";
}
// query operator
else{
// Continue parsing the tree
for ( int i = 0; i < t.getChildCount(); i++ ) {
where = printWhere((CommonTree)t.getChild(i), where ) + "QO";
}
}
//---------------------
return where;
}
The problem is that you method printWhere does not return anything! You're appending the value to new where string, but since Java passes parameters by value, this newly created string is thrown away when you leave the method.
Make this method return string and return where at the end of it. Then, concatenate the result of a recursive call with the string from the above level. That's how recursion works.

Categories

Resources