Currently I'm creating a method to reverse a linkedlist in java, but it requires two methods:
public void reverse(){
reverse(head);
}
private void reverse(Node h){
if(h.next==null){
System.out.print(h.data+" ");
return;
}
reverse(h.next);
System.out.print(h.data+" ");
}
This way I call the reverse method with 0 parameters, which then calls the other reverse method. Is there any way to make them 1 method without changing the other aspects of my LinkedList class?
Thanks in advance!
It is very common to have a public method calling a private recursive method with extra parameter(s). See the source code for Arrays.deepToString(Object[]) for an example of this.
However, in your case it may be better to avoid recursion completely. One problem with recursion is that you are only able to nest method calls to a certain depth before you get a StackOverflowError.
An alternative is to use loops instead. The following would work:
public void reverse(){
List<Node> nodes = new ArrayList<>();
for (Node n = head; n != null; n = n.next)
nodes.add(n);
for (int i = nodes.size() - 1; i >= 0; i--)
System.out.print(nodes.get(i).data + " ");
}
Technically, there is a way, but I would not recommend it. This is it:
public void reverse( Node... nodes )
{
Node h;
if( nodes.length == 0 )
h = head;
else
{
assert nodes.length == 1;
h = nodes[0];
}
if( h.next == null )
{
System.out.print( h.data + " " );
return;
}
reverse( h.next );
System.out.print( h.data + " " );
}
Note that this would also require making class Node public, which is also not a good idea. (Or you might just get a warning for having a public method accepting a parameter of a private type, which you can then suppress; I don't remember.)
But Paul Boddington's comment is right on the money.
Paul beat me to a similar answer, but I figured I'd post mine anyways since I assumed that you do not want to use ArrayList as a dependency:
Yes it is possible. If it is a doubly linked list you could traverse the list to the last node then walk the list to the front. However, I will also assume it's a single linked list, so I'll answer using an array to store all node references. Also, I assume you have another method to calculate length.
public void reverse() {
int length = length();
Node [] nodes = new Node[length];
Node currentNode = head;
int i = 0;
// Populate the array
while(currentNode != null)
{
nodes[i] = currentNode;
currentNode = currentNode.next;
i++;
}
// Iterate backwards to print the array
for(int j = length -1; j >= 0; j--)
{
System.out.println(nodes[i] + " ");
}
}
Yes. You can make the parameter in your displayed second method "act" as an Optional Parameter. In the method declaration below we're in essence making the Node Type parameter to be an Node array which can be passed as empty. Since we're only need to pass 1 parameter to our method then we only need the supplied Node data contained in the element Index of 0 (the first element of the array).
Within the method itself we declare a Node variable which was the same type and name as what your parameter was so to eliminate any confusion within the code body of the method and we provide a default of 0 (default can be whatever you want). We then check the new headerInfo[] array parameter to see if there was anything supplied and if there was then we apply that data from the first element of the headerInfo[] array (since we're only using one parameter for this method) to the new Node type variable h. The args[] parameter for the main method in a class does the same thing.
public void reverse(Node... headerInfo){
Node h = 0;
if (headerinfo.length != 0) { h = headerInfo[0]; }
if(h.next==null){
System.out.print(h.data+" ");
return;
}
reverse(h.next);
System.out.print(h.data+" ");
}
Now the method can be can be called as reverse() or reverse(head)
EDIT:
Whops...Mike beat me to it :)
Related
I need to write a Java method called findMax within a class called Node, which has two instance variables: int value and Node next. The method takes no parameters, and must return the greatest value of a linked list. Within the context of the program, the method will always be called by the first Node of a linked list (except for the recursive calls). I was struggling to complete the method when I accidentally found a working solution:
public int findMax(){
int max = value;
if(next == null){
return max;
}
else{
if(max <= next.findMax()){
max = next.value;
}
else return max;
}
return next.findMax();
}
This method properly returned the largest value of each linked list I tested it for. However, since I found this solution by trying random arrangements of code, I don't really feel like I understand what's going on here. Can anyone explain to me how/why this works? Also, if there is a more efficient solution, how would it be implemented?
You can imagine a linked list looking something like this:
val1 -> val2 -> val3 -> null
Recursion works on the principle that eventually, the input you pass into the function can be handled without recursing further. In your case, node.findMax() can be handled if the next pointer is null. That is, the max of a linked list of size 1 is simply the value (base case of the recursion), the max of any other linked list is the max of the value of that node or the max of the remaining elements.
ie) for the Node n3 with value val3, n3.findMax() simply returns the value
For any other node n, n.findMax() returns the maximum of the node's value or n.next.findMax()
The way this looks in the example at the start is:
n1.findMax()
= Max(n1.value, n2.findMax())
= Max(val1, Max(n2.value, n3.findMax())
= Max(val1, Max(val2, n3.value)) // Since n3.next == null
= Max(val1, Max(val2, val3))
which is simply the maximum over the whole list
Edit: Based on the discussion above, although what you said might work, there is a simpler way of writing the program:
int findMax() {
if (this.next == null) {
return this.value;
} else {
return Math.max(this.value, this.next.findMax());
}
}
Edit 2: A break down of why your code works (and why it's bad):
public int findMax(){
// This variable doesn't serve much purpose
int max = value;
if(next == null){
return max;
}
else{
// This if condition simply prevents us from following
// the else block below but the stuff inside does nothing.
if(max <= next.findMax()){
// max is never used again if you are here.
max = next.value;
}
else return max;
}
// We now compute findMax() again, leading to serious inefficiency
return next.findMax();
}
Why is this inefficient? Because each call to findMax() on a node makes two subsequent calls to findMax() on the next node. Each of those calls will generate two more calls, etc.
The way to fix this up is by storing the result of next.findMax() like so:
public int findMax() {
if (next == null) {
return value;
}
else {
int maxOfRest = next.findMax();
if(value <= maxOfRest) {
return maxOfRest;
}
else return value;
}
}
Ok so i need to deleted items from a circular list,as part of a bigger program that isnt working, and i cant seem to delete the last node passed in to the delete method, if the index passed in is 1 it will delete the 1st node in list and replace it, but when there is only one node left it has nothing to reference off, been at this hours. i will leave my delete method here
public void delete(int index)
{
if(Node.numOfUsers == 1)
{
first=null;
return;
}
//make curr the same as first node
int i = 1;
curr=first;
//if index passed in is 1, make temporary node same as one after first node
// if(size<1)
// {
// System.out.println("ok so this is where we are at");
// }
if(index==1)
{
temp=first.nextNode;
while(temp.nextNode!=first)
{
temp=temp.nextNode;
}
temp.nextNode=temp.nextNode.nextNode;
first=curr.nextNode;
}
else
{
//as long as i is not equal to node index-1 move current on 1 and increment i by 1
while(i != index-1)
{
curr=curr.nextNode;
i++;
}
//curr.nextNode is pointing to the node index we want and making it equal to one index above it
curr.nextNode=curr.nextNode.nextNode;
}
Node.numOfUsers--;
int size=size();
}
}
Looks like you're keeping track globally of a number of users. If this behaves the way I think it would, you could just have a small check at the beginning of this method so that if it is zero, you don't follow through with any of the logic following it.
if(Node.numOfUsers == 0) return;
This will make it so you don't bother executing any of the other logic.
A slightly better methodology to this problem might be to use the Node you want to delete as a parameter, rather than its index. This way you can avoid having to keep track of indices inside your data structure.
e.g.
public void delete(Node n) {
if(Node.numOfUsers == 0 || n == null) return; // 0 nodes or null parameter.
Node temp = first;
if(temp.next == null) { //only one node
temp = null; //simply delete it
} else {
while(temp.next != n) {
temp = temp.next;
if(temp == first) { //if we circle the entire list and don't find n, it doesn't exist.
return;
}
}
temp.next = n.next; // perform the switch, deleting n
}
}
EDIT: The above code follows the assumption that you'll have references to the node you want to delete. If this is not the case, using indices is just as good. You may also consider comparing values, however this would require you to assume that you have unique values in your nodes (and I don't know what you're restrictions are).
The logic for comparing values would be identical to the above, however instead of comparing if(temp == n) for example, you would compare if(temp.data.equals(n.data)). The use of the .equals() method is specifically for the String type, but you could modify it to work with whatever data type you are expecting, or better yet write a custom .equals method that allows the use of Generics for your abstract data type.
I have the following recursive method in a class called ImageNode which is passed the head(this - the start of the linked list) from a class called Image.
I thought my code would recursively go through each node, increase the count then when its at the end return the count, unfortunatly not. Where am I going wrong?
private int countRec() {
int count = 1;
ImageNode node = this;
if (node.next != null ){
node = node.next;
count++;
countRec();
}
return count;
}
You're ignoring the result of countRec() - and you're iterating within the recursive call, defeating the purpose. (You're also making a recursive call on the same object, with no parameters and no change in state... so that can't do any good.) My recursive approach would be based on a design of:
If the next node is null, then the size of the list is 1
Otherwise, the size is 1 + the size from the next node onwards.
So:
private int countRec() {
return next == null ? 1 : 1 + next.countRec();
}
Now that doesn't allow for a list of length 0 of course... you probably want to separate the idea of the list from the node, in which case the list class would have something like:
public int count() {
return head == null ? 0 : head.countRec();
}
where the value of head is a reference to the head node if there is one, or null otherwise.
Of course, this will be O(n) in time and space. You can get O(1) space using iteration instead of recursion, and O(1) time by just keeping the size of the list as an instance variable in the list, updating it when you need to. I'm hoping that this question was based on an educational requirement rather than real code though - in production code, you'd just use the collections provided already.
The definition of a recursive function is it is defined in terms of itself: i.e. the count of elements in a list is equal to 0 if an empty list; otherwise it is equal to 1 + the count of the rest of the elements of the list.
The italicized portion of the above definition is where the function call gets made.
private int countRec(ImageNode node) {
if (node == null) {
return 0;
} else {
return 1 + countRec(node);
}
}
A recursive function is useful when it uses the result of the further calls to solve his problem (like an inductive step on mathematics). Your function are not using the return for the countRec() call for anything, and you're still trying to solve the issue without the recursion help. You can solve it by using it, as:
if(node.next != null)
{
node = node.next;
count = countRec()+1;
}
return count;
Of course, since we're telling about getting your code better, you wouldn't even need to use this node var, just doing:
private int countRec() {
if (this.next != null )
return (this.next.countRec())+1;
return 1;
}
Hope that helps.
As a part of exercise, i am writing a recursive code to count the number of nodes in a queue. The code part which I have added/modified (in NodeQueue.java) is here:
public class NodeQueue implements Queue
{
static protected int count; //for RecNodeCount method only
protected Node beingCountedNode = head; //for RecNodeCount method only
// other methods..
public int RecNodeCount()
{
if(beingCountedNode == null)
return count;
else
{
count++;
beingCountedNode = beingCountedNode.getNext();
return RecNodeCount();
}
}
The entire code is as here:
Queue.java: http://pastebin.com/raw.php?i=Dpkd8ynk
Node.java: http://pastebin.com/raw.php?i=Zy0KbrtJ
NodeQueue.java: http://pastebin.com/raw.php?i=j6hieiLG
SimpleQueue.java: http://pastebin.com/raw.php?i=vaTy41z4
I am unable to understand why I am getting zero even after enqueueing few nodes in the queue. The size variable returns the correct number. I am doing more or less the same with the count variable (I think!) i.e. incrementing the required variable.
Although I believe the method will work (if beingCountedNode is set properly before the call. See #peter.petrov answer), it is weird to use instance variables as parameters for a function. I think the recursive function should have the signature int Count( Node node ) which returns the number of nodes after (including) the given Node.
// returns the number of nodes in the list
public int Count(){ return CountHelper( head ); }
// helper recursive function
// returns the number of nodes in the list after and including "node".
// call with head of the list to get the count of all nodes.
private int CountHelper( Node node )
{
if( node == null )
return 0;
else
return 1 + CountHelper( node.getNext() );
}
Also note in your current example, you never reset count, so if I call RecNodeCount() twice in a row, your method will tell me the count is twice what it actually is. Edit, actually I guess it wouldn't since beingCountedNode would be null, but it is still weird to do it this way.
My guess is this following.
When this line is executed
protected Node beingCountedNode = head;
your head is null.
So beingCountedNode is set to null. Due to this,
later in your method you never enter the else clause.
Just add a few System.out.println calls in RecNodeCount()
and you'll see what exactly is happening in this method.
Maybe this is not a direct answer for your issue, but why do you even use recursive and static variable here? Is' really easy to count nodes with simple while.
public int nodeCount(Node node) {
int result = 0;
while(node != null) {
node = node.getNext();
result++;
}
return result;
}
I have this constructor that takes in a phrase of jmusic notes, and I'm trying to set each individual note to an individual node in a linked list of SoloNodes which hold one individual note only. most of the methods in that constructor I've written myself but they're pretty self explanatory. What exactly must I do to make this generate a linked list?
public Solo(Phrase myPhrase)
{
int length=myPhrase.length();
head=new SoloNode();
SoloNode next=new SoloNode();
for(int i=1; i<=length;i++)
{
head.setNote(myPhrase.getNote(i));
next=head.copyNode();
head.setNext(next);
head=next;
i++;
}
}
I guess that's the code you are looking for:
private SoloNode head;
public Solo(Phrase myPhrase)
{
int length = myPhrase.length();
SoloNode node = new SoloNode();
head = node;
for (int i = 0; i < length; i++) {
node.setNote(myPhrase.getNote(i));
if (i + 1 < length) {
node.setNext(new SoloNode());
node = node.getNext();
}
}
}
I assumed you are using a class SoloNode which looks like this.
I assumed too that myPhrase.getNote(i) starts with index 0 (not 1) because that is the common way how it works in Java.
After you run this code the SoloNodes are filled with data from myPhrase and linked from one to next. With getNext() you can navigate from current to next. Only for last SoloNode it will return null.