Does iterator violate stack/queue data structure? - java

As we know in Java each class that implements Collection interface should implement Iterator<E> iterator() method.
Stack and Queue are parts of collection hierarchy and implement this method as well. So we can write something like this:
Stack stack = new Stack();
// Deque stack = new ArrayDeque<>();
stack.add( "1" );
stack.add( "2" );
stack.add( "3" );
Iterator i = stack.iterator();
while ( i.hasNext() ) {
Object o = i.next();
if ( o.equals( "2" ) ) {
i.remove();
}
}
My concerns here are:
Is it ok that we are able to delete elements from the middle of the stack/queue?
Is it ok that stack/queue should "show" only one element (last in stack and first in queue) but actually we are able to get all of them without calling "pop","enqueue" methods?

In the strictest sense, Stack and Queue should not allow iteration over it's element but the only reason this restriction exists is to justify the existence of these data structures. As per sgi
Stack does not allow iteration through its elements.
This restriction is the only reason for stack to exist at all. Note that any Front Insertion Sequence or Back Insertion Sequence can be used as a stack; in the case of vector, for example, the stack operations are the member functions back, push_back, and pop_back. The only reason to use the container adaptor stack instead is to make it clear that you are performing only stack operations, and no other operations.
While some implementations follow this, for example std::stack in C++ does not expose iterator, other implementation provide iterators as a feature. Stack in java is built on top of Vector which implements iterator. Queue is built on top of Collection which requires iterator to be implemented. To answer your questions
Is it ok that we are able to delete elements from the middle of the stack/queue?
Yes. The underlying implementation will make sure that your stack/queue is in a consistent state after the deletion.
Is it ok that stack/queue should "show" only one element (last in stack and first in queue) but actually we are able to get all of them without calling "pop","enqueue" methods?
Yes it's a feature of the underlying implementation.

Is it ok that we are able to delete elements from the middle of the
stack/queue?
Yes since stack/queue both will keep their contract even after deleting , after all the methods exposed by stack/queue manipulate the internal implementation which is used for the deletion
Is it ok that stack/queue should "show" only one element (last in
stack and first in queue) but actually we are able to get all of them
without calling "pop","enqueu" methods?
Yes you are not violating either contract since the remove is done throw iterator interface of the element not queue or stack

Related

How to get forward iterator that starts from the last element

I have a LinkedList. Suppose that I'm inserting an element at the end and I want to save the position where was it inserted, so that I can call a function on an element next to it, whatever manages to get into this collection later. Is it possible with Java iterators? Many thanks.
Just to recollect, I'm not interested in reverse iteration. The application will be multithreaded, hence the weird requirement.
You can call List#listIterator(int index) with index = size() -1 to get an iterator to the current last element of the list. See documentation: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html
However, you are going to be stuck from there.
Whether the List implementation you are using isn't thread-safe, which is the case for LinkedList, ArrayList and most others, and any attempt to use the iterator after the list has been structurally modified is going to result in a ConcurrentModificationException being thrown.
A list is structurally modified when its size changes, i.e. on additions and removals.
Or the List implementation you are using is thread-safe, in which case you have no guaranty that the iterator will have access to the elements added to the list after the creation of the iterator.
For example, it wouldn't be the case with CopyOnWriteArrayList, for which the iterator iterates through data as it was at creation (like a snapshot).
You must find an implementation of List that clearly describe this behavior and explicitly say it in its documentation. As far as I know, there doesn't exist any that allow it, at least in the standard library.

How is it justified to use iterator with stack in Java

As we know that stack is a data structure which follows LIFO order. And as per my knowledge stack allows to access top element only. But in Java we can use iterator with stack which somehow contradict the above idea of allowing access to only top element.
Sample code
Stack<Integer> s=new Stack<Integer>();
s.push(10);
s.push(20);
s.push(30);
------------------------------------------------------------------------
Iterator<Integer> itr=s.iterator();
while(itr.hasNext())
{
System.out.print(itr.next() + " "); // ouput:- 10 20 30
}
Now I have an iterator on stack which can traverse the stack in FIFO order and I can even delete any element by using itr.remove()
It's very confusing :)
Please explain...
PS: In case I use listIterator at the place of iterator then it's even more confusing because former one provides more methods.
Java Stack<T> provides more operations than the abstract stack data type. Most likely, this is done for historical reasons, because Stack has been part of Java 1.0, and its designers decided to derive it from Vector. This is how operations from Vector became operations on Stack. Once you allow additional public operations to a public class, there is no way to take them back.
This does not mean, however, that the class is somehow broken: if you do not want the additional operations provided by Vector<T>, do not use them in your code.

Why java Iterator interface should be implemented as inner class?

I recently read a book "The Java Tutorials" 3rd edition.
It talks about inner class implementation as the picture shows.
In the 3rd paragraph, it says "The Stack class itself should not implement the Iterator interface, because...".
I cannot find any reason that Stack class should not implement Iterator. The reason given is NOT persvasive.
Could you explain it?
Fundamentally, an iterator is stateful - it needs to know where it's pointing within the collection. That doesn't belong as part of the collection itself - and the explanation given is the right one... it's entirely possible to have two independent iterator objects, iterating over the same collection object. How would you model that if the collection itself implemented the Iterator interface? It's possible (e.g. creating a new instance of the collection which in turn held a reference to the original collection), but it would be really ugly.
There are separate concerns here:
The collection of data
A cursor positioned within the collection
Separate concerns => separate classes.
The simplest way of persuading yourself of this is probably to try to implement your own collection though - and then have multiple iterators. For example, you might want to try:
List<String> foo = new MyListImplementation<String>();
foo.add("a");
foo.add("b");
// The enhanced for loop uses Iterable/Iterator for non-arrays
for (String x : foo) {
for (String y : foo) {
System.out.println(x + " " + y);
}
}
That should print out:
a a
a b
b a
b b
Try implementing it without having two classes, and see how you do, bearing separation of concerns in mind.
The stack should not implement Iterator itself because then you could have only one iterator at a time, and iterating over a stack would change the stack.
For the latter issue, notice that the nested class has a "currentItem" field. This field would need to be in "Stack", and would change when next() is called. Iterating over a collection should not change the collection.
The first problem is more serious: suppose two people iterate over the stack (or one method wishes to create two iterators over the stack). Then if iterator() returned this, the two iterators would be the same thing. Calling next() on one would move the other. Chaos.
A Stack cannot be its own Iterator because a Stack supports more than one Iterator.
You might want to iterate over the Stack more than once. These iterations might occur at different times, or even the same time. Multiple iterations at the same time clearly require multiple objects. Multiple iterations at different times require multiple objects because the Iterator interface does not support returning to the start.
There are 2 reasons I can think of off the top of my head.
Multiple types of iterators
You may want multiple types of iterators that iterate in different ways. For instance, both a Forward Iterator and a Backward Iterator (iterates from end of the container to beginning).
Multiple instances of iterators
If you have a multiple pass algorithm and/or nested loops, each loop may want its own iterator that keeps track of where it is in the container independent of the other iterators.
It would be difficult if not impossible to support these functionalities with the Iterator interface implemented in the Stack class.
Just to add to the discussion, the inner class will have access to private data of the Stack class, so in this way, the Stack class will manage to handle the client programmer an object, or multiple objects(the iterator(s), and still these object will be able to access the class and to provide separate iteration over the collection.

Why LinkedList.removeFirst() = LinkedList.pop()?

I can not understand this.
When we call LinkedList.add(), we add an element to the end of the list, so if we want to mimic a stack with a linked list, we should call LinkedList.removeLast() for pop. I just can not understand why removeFirst() is used for pop?
Assuming my psychic abilities are correct, and you're using Java:
A list (which implements Deque) can be treated as either FILO (e.g. stack) or FIFO (e.g. queue), with seperate sets of methods for each.
In either case, you remove from the front.
When treating it as a stack you use push, to add to the front.
When treating it as a queue you use add to add to the end.

How to pop items from a collection in Java?

Is there a method in JDK or apache commons to "pop" a list of elements from a java.util.List? I mean, remove the list of elements and return it, like this method:
public Collection pop(Collection elementsToPop, Collection elements) {
Collection popped = new ArrayList();
for (Object object : elementsToPop) {
if (elements.contains(object)) {
elements.remove(object);
popped.add(object);
}
}
return popped;
}
If you're looking for a stack-like structure I suggest accepting a Deque (LinkedList is the most common implementation) instead of a Collection.
If you don't actually need to treat it as a stack, just get an iterator from the Collection and use the remove() method:
for (Iterator<SomeType> it = elements.iterator(); it.hasNext(); ) {
SomeType e = it.next();
it.remove();
popped.add(e);
}
Do note that remove is an optional operation, and some implementations may throw an UnsupportedOperationException (for example, the iterator returned by a Collection from Collections.unmodifiable...() will).
Edit: After looking more closely at your question, I think you just need this:
elements.removeAll(elementsToRemove);
If your main point is you need to know exactly which elements were actually popped, I think you're stuck with your original code.
There is no such method in the standard JDK-provided methods. Apache Commons provides the ListUtils.subtract() method.
Edit: As other answerers have noted, your use of the term pop is nonstandard. Usually,
The pop operation removes an item from the top of [a stack]
Wikipedia has a nice description of stacks.
I guess no, because you definition of 'pop' operation is highly non-standard. Usually it takes no arguments (except collection itself) and returns and removes the top-most one.
But once you noted apache commons, this would achieve the same effect as your code.
Collection result = CollectionUtils.intersection(a, b);
a.removeAll(b);
edit
http://commons.apache.org/collections/api-release/index.html
Linked List provides the functionality as you require, provides a push and pop method.
Refer to the documentation as provided:
There isn't a method exactly like what you are asking for, but it looks like you are already pretty close with your code.
Some suggestions:
Consider using removeAll(object) instead of remove(object) if elements is an arbitrary collection since you may need to remove duplicates e.g. if elements is a list.
contains() is slow for some collection types (e.g. lists) since it needs to traverse the entire data structure. Given that this is in your inner loop you are at risk of O(n^2) performance issues. If you can make the algorithm work with a HashSet or HashMap then contains() will by O(1) and your algorithm will be much more efficient.

Categories