The Iterator interface - java

I have a University assignement that requires me to implement an inner class which implements the Iterator interface. The iterator works on a single-linked list superclass.
Currently my inner class looks like this:
private class ListIterator implements Iterator<V>{
Node temp;
boolean nextCalled = false;
ListIterator(Node fo){
this.temp = fo;
}
#Override
public boolean hasNext() {
if(temp != null){
return true;
}
return false;
}
#Override
public V next() {
nextCalled = true;
return temp.getReprValue();
}
#Override
public void remove() {
if(nextCalled && hasNext()){
nextCalled = false;
removeElement(temp.getReprKey());
temp = temp.getNext();
}
}
}
Now my problem is that the hasNext() method returns true even when the list is actually empty. Everything else seems to work. I have probably overlooked a logic flaw somewhere, but I cannot find it myself.

Changed your implementation to reflect what the Iterator contract needs. You need to remember that you need to be able to iterate over all elements of the collection, i.e., next() should start from the first element and after every call it must change the current next element to the next element in the list or throw an exception if there's none.
It's good to read the Iterator interface doc to undestand the way you need to implement it and start from there.
private class ListIterator implements Iterator<V> {
private Node next;
private boolean alreadyDeleted = false;
ListIterator(Node node){
this.next = node;
}
#Override
public boolean hasNext() {
// because next is the current element. We need to iterate over all the elements
// from the collection.
return next != null;
}
#Override
public V next() {
if (next == null) {
throw new NoSuchElementException();
}
Node current = next;
this.next = current.getNext();
this.alreadyDeleted = false; // it's better to try to elimate this state variable. You can try to do in another way, if yours removeElement returns something
return current;
}
#Override
public void remove() {
if (alreadyDeleted || next == null) {
throw new IllegalStateException();
}
removeElement(next.getReprKey());
this.alreadyRemoved = true;
}
}

You need to keep track of where you are in your list, implement a cursor, or if your nodes in the linked list are aware of their next, just ask them if they have a next element.
When the cursor is bigger then the length / your node has no next you return false in hasNext().
Do all this in your hasNext() method. Remember, it's okay to have next() throw an exception if hasNext() would have been false - so you need to make sure that's the only time it will throw an exception.
As I don't know the underlying data structure of your list, I can't tell you which one of these will be better.

hasNext returns true if the current node (temp) is not null.
If your linked list implementation uses a header node, then the constructor always receives fo!=null and hasNext will return true even though the list is empty. You should consider this fact in your implementation.
Based on your code, it seem that
ListIterator(Node fo){
this.temp = fo.getNext();
}
may do the trick (if header.getNext()==null for an empty list).

To reduce some code, and make it a touch more readable
rename temp to next,
use shortcut notation,
probably should have some concept of the current node,
which makes the update look like:
private Node next;
private Node current; //track deletion
#Override
public boolean hasNext() {
return next != null;
}
public Node getNext() {
if (hasNext()) {
current = next;
next = next.getNextNode();
}
return current;
}
the delete could set current to null. We don't need a flag (assuming that we're fine with doing nothing if a person deletes prior to calling the first getNext(). Heck, if we really want to go for the gold, have remove() throw an IllegalStateException if current == null.

Related

Coding the remove() method in ListIterator

I am creating a double-linked list (has a previous and next pointer) from scratch using nodes. I'm trying to write the methods to implement a ListIterator and I'm having trouble figuring out how to write the remove method. I know it is probably something really simple but I don't have a lot of experience with iterators and I can't find a tutorial or post on this anywhere.
private Node<E> cur;
private Node<E> head;
public E next() {
if(size == 0) throw new NoSuchElementException();
if(cur.next == null) throw new NoSuchElementException();
return cur.next.value;
}
public boolean hasNext() {
boolean flag = cur != null;
return flag;
}
public void remove() {
//??????????????????
}
To delete a node, the prev node needs to point to next node, and vice versa (respective to current) . That's it. Pretty simple.
Edge cases to consider:
Deleting head node
Deleting tail node
Deleting last remaining node
I hope this is enough for you to code it yourself.

finding loop in linked list using HashMap in java

i am writing code for lop detection in linked list using hashmap. why it goes in infinite loop?
boolean hasCycle(Node head) {
HashMap<Integer,Node> map = new HashMap<Integer,Node>();
//<Address,data>
if(head == null || head.next == null)
return false;
Node p = head;
while(p.next!=null)
{
if(map.containsValue(p.next))
{
return true;
}
else
{
map.put(p.data,p.next);
}
p = p.next;
}
return false;
}
Use the Node as key and the data field as value and then check whether the HashMap contains the key:
boolean hasCycle(Node head) {
HashMap<Node,Integer> map = new HashMap<Node,Integer>();
if(head == null || head.next == null)
return false;
Node p = head;
while(p.next!=null) {
if (map.containsKey(p.next)) {
return true;
} else {
map.put(p.next,p.data);
}
p = p.next;
}
return false;
}
And also follow the Java Code Conventions.
Your code calls
map.containsValue(p.next)
This method iterates through the whole map looking for an object that is equal to the passed argument. To do that, it calls your Node.equals() method. It is highly probable that this is where it's going into an infinite loop.
To solve it, you could just use a HashSet of the Node objects (as mentioned in the comments) and check that your equals() and hashCode() methods are correct. But there is also another way to check for cycles, which doesn't involve the use of any extra memory. You just use two iterators, one going at half the speed of the other. If there is a cycle, the faster iterator will lap the slower one.
Have you defined .equals() and .hashCode() on your Node class? if not, it defaults to ==, and if the HashMap makes a copy of your Node as it inserts or moves it in memory, and then your equivalence would fail, because == compares memory addresses.
assuming your node class is akin to
public class Node{
public int data;
public Node next;
}
you could define them as
#Override
public int hashCode(){
int nextData=next.data;
return data^nextData;
}
#Override
public boolean equals(Object other){
boolean equal=false;
if(other!=null&&other instanceof Node){
Node otherNode=(Node)other;
if(otherNode.data==data){
if(otherNode.next==null&&next==null){
equal=true;
}else if(otherNode.next!=null&&next!=null){
if(otherNode.next.data==next.data){
equal=true;
}
}
}
}
return equal;
}

Add to front method of linked list if there are no duplicate items, otherwise remove the duplicate item

I am having a lot of difficulty figuring out the add method of a linked list. My assignment says to:
Implement this method, public void add(E item), inside MoveToFront
class. The method behaves like this: when the input does not exist in
the linked list, add it at the front; otherwise remove the existing
one from the list and reinsert it to the front.
What I have done so far is create a contains and delete method that will search for the existing item in the list and then delete it. Then it will add the item to the front of the list.
public int getLength() {
Node<E> curNode = first;
int count = 0;
while (curNode != null) {
curNode = curNode.next;
count++;
}
return count;
}
public boolean Contains(E item) {
if (first == null) {
return false;
}
Node<E> currentNode = first;
while (currentNode.next != null) {
containCount++;
if (currentNode.item.equals(item)) {
return true;
}
currentNode = currentNode.next;
}
return false;
}
public E Delete(int kth) {
if (kth <= getLength()) {
Node<E> currentNode = first;
for (int i = 1; i < kth; i++) {
currentNode = currentNode.next;
}
currentNode.next = currentNode.next.next;
return currentNode.item;
} else {
return null;
}
}
public void add(E item) {
if (!Contains(item)) {
Node<E> myNode = new Node<E>(item, null);
first = myNode;
} else {
Delete(containCount);
Node<E> myNode = new Node<E>(item, null);
first = myNode;
}
}
I think you aren't properly linking the nodes. Before you set the node you're inserting as the first node, set the node's next to the old first, like this:
myNode.next = first;
first = myNode;
A couple of things:
Instead of going through the list twice to first check if it contains the item, then to find and delete it, you can rewrite delete() to just go through the list and delete if a matching item is found. You can then call this method at the beginning of your add() method.
You should keep track of the size of the list with a simple instance variable that is updated whenever an item is added or removed, and then just let getLength() return this. Going through the whole list each time is way too expensive.
First of all I see a getLength() method in your code. It is a linked list, if you are trying to get the length of it for this problem then you didn't get the data structure.
Now if we get to implementation I see from the requirement you have to add new element to the front one way or another. This is how I will do that-
Create a node and link its next to the first element of current list. This will be add method.you can do this method in the end too, it will not make much difference.
Then start searching for element in the list and if you find a match delete it. Make sure you don't match with the element you just added int the front.

Iterate through a linked list in Java while filtering directly in the next() method?

I'm having some issue with a part of my homework for CS. I need to write a Linked List in Java and then only iterate the odd numbers with an Iterator. Essentially, a forEach loop must iterate only through odd numbers.
So far I only have this in my LinkedList class:
public class Iterator implements java.util.Iterator<Integer> {
private Node nextNode;
public Iterator(){
nextNode = head_;
}
#Override
public boolean hasNext() {
return (nextNode != null);// && (nextNode.data_ % 2 != 0);
}
#Override
public Integer next() {
if (!hasNext()) throw new NoSuchElementException();
Integer data = nextNode.data_;
nextNode = nextNode.next_;
return data;
}
public void remove(){
throw new UnsupportedOperationException();
}
}
public Iterator iterator() {
return new Iterator();
}
If I uncomment && (nextNode.data_ % 2 != 0);, then only the first number ( which happens to be uneven) is printed. I've also tried to implement this in the next() method, but without success.
Please give me a tip what to try further.
//Later edit: I failed to mention that the linked list I want to filter consists of random numbers and is not sorted.
Your filter should be located inside your .next method, not .hasNext. This is simple logic: you iterate through whole list, and hasNext has to return true all times except when current element is the last one.
Edit: This should be the way to do it if you want only odd data points. I think we were assuming you wanted odd indexes to begin with.
#Override
public Integer next() {
//keep looking for an odd element as long as there is a next
while (hasNext()) {
//move to the next node
nextNode = nextNode.next_;
//check for an odd data point
if (nextNode.data_ % 2 == 1) {
//and return it
return data;
}
}
//no odd element was found
throw new NoSuchElementException();
}
We should look at the official documentation for Iterator.hasNext and Iterator.next
http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html
For hasNext we read
Returns true if the iteration has more elements
The internal structure does not matter. So we have no choice, our implementation has to check the whole linked list till it finds either an odd element or the end of the list. Also note that a call of hasNext should not change your structure.
public boolean hasNext() {
Node tempNode = nextNode; // nextNode need to stay the same
while (tempNode != null){
if (tempNode .data_ % 2 != 0){
return true;
}
tempNode = tempNode._next;
}
// if we are here, we found no element that is odd
return false;
}
Now the next method is almost the same, this time we need to advance the internal nextNode. If we fail to do it, the caller will always get the same element.
public Integer next() {
while (nextNode != null){
int data = nextNode.data;
nextNode = nextNode.next_;
if (data % 2 != 0){
return data;
}
}
//no odd element was found
throw new NoSuchElementException();
}
You have to use nextnode.next_ twice in order to get only the odd numbers. This is because you want to skip nextnode.next_ because that would always be an even number if your current one is an odd number. Additionally, your hasnext needs to check two spaces ahead

Why would this loop infinitely? (Java)

I am trying to make an add method for a linked list, but for some reason (that is not obvious to me, in fact I came here to get help finding the error) it goes into an infinite loop every time.
EDIT: I found the error, and I will keep my original code with a comment with the corrected code
public void insert(String majorName)
{
MajorNode newNode = new MajorNode(majorName, 1);
boolean inList = false;
MajorNode current = first;
if(isEmpty())
{
first = newNode;
// inList = true;
}
else
{
while(current.next != null)
{
if(current.majorName.equalsIgnoreCase(majorName))
{
current.frequency++;
inList = true;
break;
}
else
{
current = current.next;
}
}
}
if(!inList)
{
newNode.next = first;
first = newNode;
}
}
Here is my node class if it is needed:
public class MajorNode
{
public String majorName;
public int frequency;
public MajorNode next;
public MajorNode(String majorName, int frequency)
{
this.majorName = majorName;
this.frequency = frequency;
}
public String toString()
{
return majorName + " " + frequency;
}
}
On the first call to insert(), one assumes isEmpty() returns true and consequently first is set to the newNode before newNode's next field is set to the previous (null) value of first. Thus, when the list is non-empty, the loop iterates indefinitely on the last element in the list whose next field points to itself.
Out of curiosity, why are you trying to implement your own linked list functionality rather than build upon available packages (such as java.util.LinkedList<E>)?
When you create the first node you do this:
if(!inList)
{
newNode.next = first;
first = newNode;
}
This points the first nodes next at itself... hence a loop
You should be leaving the newNode.next as null for the first node, so that when you insert the second item, you reach the end of the chain..
You will have an wrong frequency if you add a node which is similar to the last node of your List. Consider this situation (adding 2 similar nodes in the empty list)
You will add a node1 in a blank list. So first & current will point to node1. (but node1.next will be null)
If you add the same node (or a node with a same majorName), you will reach to while loop (because List is not empty now). And also, you will not enter into a while loop as well. (as your current.next is still null)
and you will end up with two noes with same majorName in your list.
I would suggest to use
while(current != null)
instead of
while(current.next != null)

Categories