for homework I was asked to write a contain method for a custom linked list.
I know that the recursive method should have a base case and then the recursive case.However, I am having some trouble understanding how to write the recursive case of the method. So far this is what I have written, but my code is executing the base case more than once. Can you please give me some guidance?
public class OrderedList {
private Node first;
//Constructor
public OrderedList() {
this.first = null;
}
//Return the number of items in the list
public int size() {
int counter = 0;
Node pointer = this.first;
while (pointer != null) {
counter++;
pointer = pointer.next;
}
return counter;
}
//Return an array of copies of the stored elements
public Comparable[] getStore() {
Comparable[] elements = new Comparable[size()];
Node pointer = this.first;
if (this.first == null) {
return elements;
} else {
int i = 0;
while (pointer != null) {
elements[i] = pointer.data;
pointer = pointer.next;
i++;
}
return elements;
}
}
//true iff item matches a stored element
//Recursive
public boolean contains(Comparable item) {
//Base case
if (this.first == null) {
return false;
}
Node pointer = this.first;
this.first = this.first.next;
if (pointer.data.compareTo(item) == 0) {
return true;
}
//Recursive case
else {
boolean info = contains(item);
pointer.next = this.first;
this.first = pointer;
return info;
}
}
First of all I like to do something like this:
public boolean contains(Comparable item)
{
return containsHelper(this.first, Comparable item);
}
private boolean containsHelper(Node node, Comparable item)
{
//base case
if(node == null)
{
return false;
}
else
{
if(node.data.compareTo(item) == 0)
{
return true;
}
return containsHelper(node.next, item);
}
}
This hides implementation details from the user and it stops your list from getting overridden when you run that method.
To implement a recursive solution, you need an auxiliary method for contains. The auxiliary method should have an additional argument that is the Node from which to start testing. The public contains method should call the auxiliary method and pass this.first as the start node. The rest of the logic should then be pretty simple for you to figure out.
From what I am seeing, your code will return true once the else statemnet have been executed once. I think what you need to do is to set the boolean value to false everytime because recursion acts very much like a while loop and if the values are not updated, the base case would be executed over and over again.
Related
So, I am trying to write two overloaded remove methods for LinkedList class, where one takes an index of an element that needs to be removed and another one that takes Object that needs to be removed. But when I try to make a LinkedList of integer and call the latter method, method that takes in index is called instead. Is there any way around this??
(PS. I know you can just change the name of the method, but I am given an interface file that requires me to write overloaded methods)
public E remove(int index) {
for (int i = 0; i < index;i++) {
curNode = curNode.next();
}
if (curNode == head && curNode == tail) {
head = null;
tail = null;
}
else {
URNode sucNode = curNode.next();
URNode prevNode = curNode.prev();
if (sucNode != null)
sucNode.setPrev(prevNode);
else {
prevNode.setNext(null);
tail = prevNode;
}
if (prevNode != null)
prevNode.setNext(sucNode);
else {
sucNode.setPrev(null);
head = sucNode;
}
}
numElements--;
return null;
}
public boolean remove(Object o) {
URNode curNode = head;
for (int i = 0; i < numElements;i++) {
if (curNode.element() == o) {
remove(i);
return true;
}
curNode = curNode.next();
}
return false;
}
public static void main(String args[]){
LinkedList intList = new LinkedList();
intList.add(1);
intList.add(2);
intList.add(3);
intList.remove(1); //I want this to remove node with element 1, instead of node with index of 1
//[2][3] should be returned, not [1][3]
}
intList.remove(Integer.valueOf(1)); // just make it Integer but not int
I was asked to write a method that runs on a Linked List and checks if 2 of the lists contain the same values (It doesn't have to be the same order of values between them both).
Here's my code:
public boolean Equals(Object obj) {
if(obj instanceof LinkedList) //Checks if the object it got is a Linked List
{
if(this.length() != ((LinkedList)obj).length())
return false;
Node head1 = head;
Node head2 = ((LinkedList) obj).getHead();
boolean ans = false;
this.toString();
((LinkedList)obj).toString();
while(head1 != null)// Running on the 1st list values
{
while(head2 != null) { // comparing each value in the 2nd list to see if it's on the 1st list as well
if(head2.getValue() == head1.getValue())
ans = true;
head2 = head2.getNext();
}
if(ans == false)
return false;
ans = false;
head1 = head1.getNext();
}
return true;
}
else
return false;
}
I'm adding also the structure's class that you wouldn't have any difficulties on understanding:
public class LinkedList {
// Attributes
private Node head, tail;
private int length;
// Constructor
public LinkedList() {
head = tail = null;
length = 0;
}
// getHead
public Node getHead() {
return head;
}
// getTail
public Node getTail() {
return tail;
}
// Length
public int length() {
return length;
}
// isEmpty
public boolean isEmpty() {
return head == null;
}
It returns false on all the cases no matter what, I don't manage to enter my error, thanks a lot!!
Your solution wouldn't work , if the lists are of type -
list A : 1 -> 1 -> 1
list B : 1 -> 2 -> 3
because in 2nd while loop , ans will set to true , because it will match 1 to 1.
to solve your problem - you need to sort both lists and then compare.
Or you can use hashing to compare if both lists are equal.
For Homework I was told to write the insert method(in order) of a custom linked list. I wrote the base case, but I still don't understand the recursion case. I know I just asked how to write the contain method and someone helped me out, but in that case I did not have to do any modifications to the list like on this method. Please help me understand what is causing my linked list to override and if there is an easier way to simplify my code.
Here is my code:
public class OrderedList {
private Node first;
//Constructor
public OrderedList() {
this.first = null;
}
//Return the number of items in the list
public int size() {
int counter = 0;
Node pointer = this.first;
while (pointer != null) {
counter++;
pointer = pointer.next;
}
return counter;
}
//Return an array of copies of the stored elements
public Comparable[] getStore() {
Comparable[] elements = new Comparable[size()];
Node pointer = this.first;
if (this.first == null) {
return elements;
} else {
int i = 0;
while (pointer != null) {
elements[i] = pointer.data;
pointer = pointer.next;
i++;
}
return elements;
}
}
//true iff item matches a stored element
//Recursive
public boolean contains(Comparable item) {
return containsHelper(this.first, item);
}
private boolean containsHelper(Node node, Comparable item) {
//base case
if (node == null) {
return false;
} else {
if (node.data.compareTo(item) == 0) {
return true;
}
return containsHelper(node.next, item);
}
}
//Add item preserving the order of the elements
//Recursive
public void insert(Comparable item) {
insertHelper(this.first, item);
}
public void insertHelper(Node pointer, Comparable item) {
//Base case
Node store = new Node(item);
if (pointer == null) {
store.next = this.first;
this.first = store;
return;
}
if (pointer.data.compareTo(item) > 0 ) {
store.next = pointer;
return;
}
if (pointer.data.compareTo(item) < 0 && pointer.next == null) {
store.next = pointer.next;
pointer.next = store;
return;
} else {
Node save = this.first;
this.first = this.first.next;
insertHelper(this.first, item);
if (pointer.data.compareTo(item) > 0) {
save.next = store;
this.first = save;
} else {
save.next = pointer;
this.first = save;
}
}
}
I'm only giving you part of the answer at first. Consider this a clue. Then there are more clues. See if you can figure it out before you get to the bottom where a whole answer is.
clue 1
This part of the code can't be in the recursive method because it makes reference to the head of the linked list. Your recursion is moving down the list, breaking it into the head and the rest, deciding whether to insert at the head and recursing if the insertion has to be in the rest.
if (pointer == null) {
store.next = this.first;
this.first = store;
return;
}
This should be modified a bit so it can go in the insert() method, which deals with the whole list.
Why?
Because this code deals with the whole list and asks the question, "Is this list empty?"
clue 2
Now, for this part of the code:
if (pointer.data.compareTo(item) > 0 ) {
store.next = pointer;
return;
}
Notice how it has a reference to the whole list. That's a bad thing.
Its asking the question, "Is the new item (to be inserted) supposed to go in front of the current head item?"
If the answer is yes, it needs to insert it in front of the current head, leave the current head with the current rest of the linked list attached as before and return something that lets the calling code attach a newly arranged rest of the list.
if (pointer.data.compareTo(item) > 0 ) {
store.next = pointer; // new item goes in front of this part of list
return store;
}
clue 3
Now, let's skip to this part of the code:
Node save = this.first;
this.first = this.first.next;
insertHelper(this.first, item);
if (pointer.data.compareTo(item) > 0) {
save.next = store;
this.first = save;
} else {
save.next = pointer;
this.first = save;
}
This code asks no questions. It just recurses since we know that no change is needed related to the head of the current linked list. When we recurse, we pass it the rest of the linked list and tell it to fix that up. We don't care how because we trust it to fix up the rest of the list by inserting the new item in the right place.
So here is what we do:
Node rest = insertHelper(pointer.next, item);
pointer.next = rest;
return pointer;
clue 4
This part of the code is the last part to consider:
if (pointer.data.compareTo(item) < 0 && pointer.next == null) {
store.next = pointer.next;
pointer.next = store;
return;
}
Now, think about why you are comparing it again. The previous code tested whether the item needed to go in front of the rest of the linked list. The answer was no.
That means there are only two possible situations left.
Either there is nothing left in the list ... and we have to put the new item on the end.
Or there is something in the list ... and clue 3 deals with that by recursing.
So this part gets a little simpler:
if (pointer.next == null) {
return store;
}
All we have to do is return the new node which will be the new "rest of the list", instead of there being nothing in the rest of the list.
One more note
Remember that the method signature has to change to be like this:
/**
* Insert the 'item' into the linked list beginning with the supplied node, 'pointer'
* #returns the new, modified linked list, with the new item in it.
*/
public Node insertHelper(Node pointer, Comparable item) {
The whole thing
This includes the changes to the 'insert' method:
public void insert(Comparable item) {
// if there isn't anything in the list, the new item becomes the whole list
if (first == null) {
Node store = new Node(item);
store.next = null;
this.first = store;
return;
}
// Otherwise let the helper fix up the list for us to store away
this.first = insertHelper(this.first, item);
}
public Node insertHelper(Node pointer, Comparable item) {
Node store = new Node(item);
if (pointer.data.compareTo(item) > 0 ) {
store.next = pointer; // new item goes in front of this part of list
return store;
}
if (pointer.next == null) {
return store; // new item becomes this part of the list
}
// The head of this part of the list is ok, fix the rest of the list
pointer.next = insertHelper(pointer.next, item);
return pointer;
}
Further comments
There is another way to do this where you store the first node in some other class and each Node only stores a pointer to the rest of the list (as next).
Then you have a method to insert that knows when it gets called that it can't be null because you couldn't call it if it was null.
There is no test for the first one being null inside insert because of that. But it means the caller has to do something like:
Node item = new Node(data);
if (list != null) {
list.insert(item);
} else {
list = item;
}
and the insert method looks like this:
if (this.next == null || this.data > item.data) { // pseudo code for greater than
item.next = this.next;
this.next = item;
return;
}
this.next.insert(item);
And that's it.
I am required to write a method that returns a number - the amount of times an element is found in a linked list. So far I have;
package Question4;
import net.datastructures.Node;
public class SLinkedListExtended<E> extends SLinkedList<E> {
// returns the number of occurrences of the given element in the list
public int count(E elem) {
Node<E> cursor = tail;
int counter = 0;
if ((cursor != null) && (!(cursor.getElement().equals(elem)))) { //tail isnt null and element is not equal to elem
cursor = cursor.getNext(); //go to next node
} else if ((cursor != null) && (cursor.getElement().equals(elem))){ //cursor isn't null and element equals elem
counter++; //increment counter
}
else {
return counter; //return counter
}
return counter;
}
public static void main(String[] args) {
SLinkedListExtended<String> x = new SLinkedListExtended<String>();
x.insertAtTail("abc");
x.insertAtTail("def");
x.insertAtTail("def");
x.insertAtTail("xyz");
System.out.println(x.count("def")); // should print "2"
x.insertAtTail(null);
x.insertAtTail("def");
x.insertAtTail(null);
System.out.println(x.count("def")); // should print "3"
System.out.println(x.count(null)); // should print "2"
}
}
I have extended to a class which compiles correctly, so I know the problem is in my method. I can't figure out what to do, my code returns 0, which is probably the counter integer remaining at 0 and not going through the loop statement. Any ideas are appreciated.
Edit. SLinkedList code:
import net.datastructures.Node;
public class SLinkedList<E> {
protected Node<E> head; // head node of the list
protected Node<E> tail; // tail node of the list (if needed)
protected long size; // number of nodes in the list (if needed)
// default constructor that creates an empty list
public SLinkedList() {
head = null;
tail = null;
size = 0;
}
// update and search methods
public void insertAtHead(E element) {
head = new Node<E>(element, head);
size++;
if (size == 1) {
tail = head;
}
}
public void insertAtTail(E element) {
Node<E> newNode = new Node<E>(element, null);
if (head != null) {
tail.setNext(newNode);
} else {
head = newNode;
}
tail = newNode;
size++;
}
public static void main(String[] args) { // test
SLinkedList<String> list = new SLinkedList<String>();
list.insertAtHead("lol");
}
}
Maybe you should use a while loop instead of an if clause
**while** ((cursor != null) && (!(cursor.getElement().equals(elem)))) {
The code in count is not in a loop, so it'll just return after the first element.
Try this:
public int count(E elem) {
Node<E> cursor = tail;
int counter = 0;
while (true)
{
if ((cursor != null) && (!(cursor.getElement().equals(elem)))) { //tail isnt null and element is not equal to elem
cursor = cursor.getNext(); //go to next node
} else if ((cursor != null) && (cursor.getElement().equals(elem))){ //cursor isn't null and element equals elem
counter++; //increment counter
}
else {
return counter; //return counter
}
}
}
Also, note that cursor.getElement().equals(elem) will return a NullPointerException when cursor.getElement() is null. The easiest way to deal with this is probably to write a separate equals method:
boolean equals(E e1, E e2)
{
if (e1 == null)
return e2 == null;
if (e2 == null)
return false;
return e1.equals(e2);
}
Also, presumably Node<E> cursor = tail; makes it point to the end of the list and presumably you want Node<E> cursor = head; instead.
One of the fundamental things that you were missing was a loop. Since you are essentially searching for something, you want to loop through the entire list. Once you run into an element that matches the one that you are searching for, you want to increment the count by 1. Once you have finished looping through the entire list, you want to return that count. So this is my solution. I keep it simple so you could understand:
import java.util.LinkedList;
public class Duplicates<E> extends LinkedList<E> {
public static void main(String[] args) {
Duplicates<String> duplicates = new Duplicates<String>();
duplicates.add("abc");
duplicates.add("def");
duplicates.add("def");
duplicates.add("xyz");
System.out.println(duplicates.duplicateCount("def"));
duplicates.add(null);
duplicates.add("def");
duplicates.add(null);
System.out.println(duplicates.duplicateCount("def"));
System.out.println(duplicates.duplicateCount(null));
}
public int duplicateCount(E element) {
int count = 0;
for (E e : this) {
if (e == element) {
count++;
}
}
return count;
}
}
Output:
2
3
2
I suggest you combine Martin's answer (which tells you how to count the elements) with this, which tell you how to be able to use foreach - you just have to make your SLinkedListExtended implement Iterable, whioch should be something liek the follwoing (you could do this on SLinkedList, but I'm assuming you were told not to alter the code for that one):
public class SLinkedListExtended<E> extends SLinkedList<E> implements Iterable<E> () {
public Iterator<E> iterator() {
final Node<E> itHead = head;
return new Iterator<E>() {
Node<E> current = itHead;
long position = 0;
public boolean hasNext() {
return current != null && position < size;
}
public E next() {
current = current.getNext();
++position;
return current.getElement();
}
public void remove() {
throw new UnsupportedOperationException("Not supported yet.");
}
};
}
};
I can't vouch for all the details, but this should cover most of it. You may also consider using equals instead of ==, but don't forget to check the elements for nullity.
next should only be called if hasNext is true, so it's not a problem if it throws an exception (but it should be a NoSuchElementException to keep in line with the contract).
Implementing Iterable makes your class compatible with the Collections library, hence the support for foreach, but you can use it to do raw iteration by calling iterator, hasNext and next yourself.
I've done some exercises in Java and now I'm stuck at such a problem - my list works incorrectly. I am sure that remove works incorrectly and maybe you can help me (with advice or code) to implement a circular singly linked list in a correct way. I am not sure whether other functions work properly, but I've tried to do my best.
Here is my code:
import java.util.*;
public class Node {
private Object value;
private Object nextValue;
private Node next;
public Node(int data) {
this.value = data;
this.next = null;
}
public Object getValue() {
return this.value;
}
public Node nextItem() {
return this.next;
}
public void setNextItem(Node nextItem) {
this.next = (Node) nextItem;
this.next.setValue(nextItem.getValue());
}
public void setValue(Object arg0) {
this.value = arg0;
}
}
-------------------------------------------------------------------
import java.util.*;
public class CircularList {
private Object[] array;
private int arrSize;
private int index;
private Node head;
private Node tail;
public CircularList() {
head = null;
tail = null;
}
public boolean add(Node item) {
if (item == null) {
throw new NullPointerException("the item is null!!!");
}
if (head == null) {
head = item;
head.setNextItem(head);
arrSize++;
return true;
}
Node cur = head;
while(cur.nextItem() != head) {
if(cur.getValue() == item.getValue()) {
throw new IllegalArgumentException("the element already " +
"exists!");
}
cur = cur.nextItem();
}
head.setNextItem(item);
item.setNextItem(head);
arrSize++;
return true;
}
public Node getFirst() {
return head;
}
public void insertAfter(Node item, Node nextItem) {
if ((item == null) || (nextItem == null)) {
throw new NullPointerException("the item is nul!!!");
} else if (this.contains(nextItem) == true) {
throw new IllegalArgumentException("the item already exists!");
}
Node cur = head;
while(cur.nextItem() != head) {
if(cur.getValue() == item.getValue()) {
nextItem.setNextItem(item.nextItem());
item.setNextItem(nextItem);
} else {
cur = cur.nextItem();
}
}
}
public boolean remove(Node item) {
if(item == head) {
Node cur = head;
for(int i = 0; i < arrSize-1; i++) {
cur = cur.nextItem();
}
head = head.nextItem();
for(int i = 0; i < arrSize; i++) {
cur = cur.nextItem();
}
arrSize--;
return true;
}
Node cur = head;
int counter = 0;
while(cur.nextItem() != head) {
if(cur == item) {
item = null;
cur = cur.nextItem();
while(cur.nextItem() != head) {
cur.setNextItem(cur.nextItem().nextItem());
}
return true;
}
cur = cur.nextItem();
}
return false;
}
public int size() {
return arrSize;
}
public boolean contains(Object o) {
if ((o == null) && (arrSize == 0)) {
return false;
}
Node cur = head;
while(cur.nextItem() != head) {
if(cur.getValue() == o) {
return true;
}
cur = cur.nextItem();
}
return false;
}
}
Many of these algorithms could be simpler.
Example:
public boolean remove(Node item) {
Node current = head;
for(int i = 0; i < size; i++) {
if (current.getNext() == item) {
current.next = current.getNext().getNext();
size --;
return true;
}
current = current.getNext()
}
return false;
}
There are a variety of issues here beyond the list. You seem to be comparing your nodes with ==. This code will output 'no match'.
Node n1 = new Node(5);
Node n2 = new Node(5);
if (n1 == n2)
System.out.println("objects match");
else
System.out.println("no match");
In add(), it looks like you can only ever have two items in the list, so
head.setNextItem(item);
item.setNextItem(head);
should be this:
cur.setNextItem(item);
item.setNextItem(head);
There's a lot going on in your code, here's some advice for some of it:
In your Node class: Java naming conventions: the same way that setters should be prefixed with "set," getters should be prefixed with "get:" nextItem() should really be getNextItem().
Also in your Node class: as far as I know, the "next value" field of a node of a linked list is usually a reference to the next Node in the list, and should therefore be of type Node, not just any Object. It should work the way you have it, but using explicit typing is a lot safer. (Please correct me if using "Object" is indeed a common way to construct the next node of a linked list.)
In the first case of remove(), when removing the head: you're looping through the list to reach the last value, presumably to reset its "next value" to the new head, but you're not actually doing it. You want something like this:
if (item == head) {
head = head.nextItem();
for(int i = 0; i < arrSize-1; i++){
cur = cur.nextItem();
}
}
cur.setNextItem(head);
I'm not sure what you hope to accomplish with the second loop.
In the second case of remove(): I'm not sure what you're trying to do with the second while loop - reset all the links in the whole list? The whole point of a linked list is to make that unnecessary. Deleting a node in a linked list does not actually get rid of the object (so you don't have to set item to null). Rather, you simply "go around" the unwanted object and "ignore" it, effectively removing it from the list, as in:
Original list:
[ Value: A; Next: B ] --> [ Value: B; Next: C ] --> [ Value C; Next: D ] ...
After deleting node B:
[ Value: A; Next: C ] --> [Value C; Next: D ] ...
[ Value: B; Next: C ] still exists in memory, but nothing is pointing to it, so it will be removed in the next garbage collection cycle.
To implelement: As you walk the list, keep a reference to the previous node that you visited. Then, once you find the item you're looking for (using correct comparison, as Thomas noted), you can simply set prev.setNextItem(cur.nextItem()); (caveat: untested code):
Node prev = head;
Node cur;
while ((cur = prev.nextItem()) != head) {
if (cur.equals(item)) {
prev.setNextItem(cur.getNextItem());
return true;
}
}
I hope these tips help you along the correct path.