Java Linked List: Removing Largest Element Using Iterator - java

how can I remove the largest element from a linkedlist in java? I know I can use get() or remove() functions to retrieve / remove the elements. But I want to make it efficient. I want to use iterator. Do you have any idea how i can do it? Note that I dont want to create my own linkedlist. I dont even want to sort my linkedlist.
Can I do a linear search for this? If so, how can I keep track of the pointer (or iterator) that points to the largest element. Any help will be appreciated.

A linked list (unless sorted) is not the best structure for what you are trying to do here as you have no other option than do a linear search and remove the biggest element
Integer biggest = Integer.MIN_VALUE;
for(Integer e : myList){
if(biggest < e)
biggest = e;
}
myList.remove(biggest);
this would be O(n), even though you have to scan again to remove the biggest, this second scan would be avoidable if you did your own LinkedList because the java.util.LinkedList hides its Entry class and does not allow you to modify the pointers; but that would be the wrong way to optimize, because if instead you use a heap like structure, in java that would be PriorityQueue class, you could get O(log(n)) and reduce the code to:
return myPriorityQueue.poll();

if you know what the largest element is you can do it like so
Iterator<Integer> it = list.iterator();
Integer toRemove;
while(it.hasNext()){
if(toRemove.compareTo(it.next()==0){
it.remove();
break;
}
}
or use list.removeFirstOccurrence(toRemove)
but LinkedList implementations don't allow for copying iterators to point to specific elements for later removal

Related

How to iterate over Set and add elements to it in java?

I want to iterate over a Set and if some condition meet I want to add elements to it.
While I am doing this, I am getting "ConcurrentModificationException".
When I looked for the answer, I found that in case of listIterator we have add() and remove() method but I can't use list as I also have to take care of duplicates.
Please suggest a way to achieve this.
Edit:
int[] A = {1,2,3,4,5,10,6,7,9};
Set<Integer> s = new HashSet<>();
s.add(1);
Iterator i = s.iterator();
while(i.hasNext()){
int temp = i.next();
int x = next element of array A;
if(x%2==0){
s.add(temp*x);
}
}
But it is throwing ConcurrentModificationException.
How to iterate over Set and add elements to it in java?
It cannot be done. Certainly, not with a HashSet or TreeSet. You will probably need to find an alternative way of coding your algorithm that doesn't rely on doing that.
The normal solution is to create a temporary list, add elements to that list, then when you have finished iterating use addAll to add the list elements to the set. But that won't work here because you appear to want your iterator to see the new elements that you have added.
A second approach would be use a ConcurrentHashMap and Collections::newSetFromMap instead of a HashSet. Iterating a concurrent collection won't give a ConcurrentModificationException. However, the flipside is that there are no guarantees that the iterator will see all of the elements that were added during the iteration. So this probably wouldn't work (reliably) for your example.

Iterating from the end of a list

I know that we can iterate over the list in the reverse order as follows:
List<Object> lst;
ListIterator<Object> i = lst.listIterator(lst.size());
But is it efficient if lst is a LinkedList? I mean when we obtain the ListIterator pointing to the end of the list, does the implementation iterate over the list from the begging to the list.size() position (takes O(n) time, where n is a size of the list)?
If it does, is there a way to avoid it?
The javadoc states that LinkedList is a doubly-linked list, so I would expect descendingIterator(), which return an iterator pointing to the tail of the list, to be O(1). Note that descendingIterator is from the Deque interface.
Now it is difficult to say whether the statement lst.listIterator(lst.size()) is also O(1), because it is not documented if listIterator method optimize the fact that the next element from lst.size() is the tail.
The documentation states that LinkedList is a "Doubly-linked list implementation of the List and Deque interfaces". So every element in the list has references to both the next AND the previous elements. So, the iterator should be as quick in the reverse order as it is in the natural order.
It doesn't iterate over the list to produce the iterator.
The best place to look for solutions to these is the Source Code.
if (index < (size >> 1)) {
next = header.next;
for (nextIndex=0; nextIndex<index; nextIndex++)
next = next.next;
} else {
next = header;
for (nextIndex=size; nextIndex>index; nextIndex--)
next = next.previous;
}
As you can see, it will try to reach the index using the shortest path either from the first node or last node.
LinkedList also implements Deque interface.
So if you implement it as
Deque list = new LinkedList();
Or if you additionally need the list methods
LinkedList list = new LinkedList();
You can use
list.descendingIterator();
Your code will not work, the index lst.size() is out of bounds, maybe you meant lst.size()-1. But still it is not a reverse iterator, it is a forward iterator that instead of beginning at 0 will begin at the element you specify. In this case you will read only the last element then reach the end.
LinkedList implements interface Deque which provides Deque.descendingIterator. In this case both instancing the iterator and moving to the next (previous) element are O(1) operations. In the first case it's because the Deque implementation keeps a reference to both the beginning and the end of the queue, in the second because LinkedList is a doubly-linked list, in which every element keeps a reference to both its successor and his predecessor.

iterating through a linkedhashmap but over a certain range

So i know how to iterate through a whole linkedhashmap from the beginning, but what if I want to only link through a certain portion from it? IE: i want to start from the end and go only 4 elements back. How would I do that and is it possible?
What you are searching for is a ListIterator which would allow you to iterate backwards in a list. Unfortunately, LinkedHashMap does not hold a reference towards the previous element, and thus does not provide this iterator.
So, you end up with two solutions. One, you implement the method to find the X last elements: you hold, let's say an array (a circular buffer) of size X and keep there the last X elements you have seen. This solution is rather inefficient if you call this method frequently and for X much smaller than the size of your map.
A second solution is to keep a HashMap instead of a LinkedHashMap and an extra List to maintain the insertion order. E.g. an ArrayList or a LinkedList which provide a ListIterator and thus, backwards iteration.
You could use the ListIterator for this, by doing something like this.
List list = new ArrayList<>(map.keySet());
ListIterator li = list.listIterator(list.size());
while (li.hasPrevious()) {
System.out.println(map.get(li.previous()));
}
Since the LinkedHashMap maintains the order, you could simply create a list from the keys which are going to be in order as well. Get a ListIterator from the last index, so that you can traverse backwards having a counter(which I've not shown) to iterator till the no. of elements required.
You have to extend standard implementation and override methods that return appropriate iterator to your own.
Iterator<K> newKeyIterator() { return new KeyIterator(); }
Iterator<V> newValueIterator() { return new ValueIterator(); }
Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); }
LinkedHashMap.Entry is a doubly linked list, so you can go forward and backward as well.
LinkedHashMap.LinkedHashIterator is a base iterator for LinkedHashMap. Make what you need based on it.

Remove list elements - my approach for best performance in Java

If I need to remove elements in a list, will the following be better than using LinkedList:
int j = 0;
List list = new ArrayList(1000000);
...
// fill in the list code here
...
for (Iterator i = list.listIterator(); i.hasNext(); j++) {
if (checkCondition) {
i.remove();
i = list.listIterator(j);
}
}
?
LinkedList does "remove and add elements" more effectively than ArrayList, but LinkedList as a doubly-linked list needs more memory, since each element is wrapped as an Entry object. While I need a one-direction List interface, because I'm running over in ascending order of index.
The answer is: it depends on the frequency and distribution of your add and removes. If you have to do only a single remove infrequently, then you might use a linked list. However, the main killer for an ArrayList over a LinkedList is constant time random access. You can't really do this with a normal linked list (however, look at a skip list for some inspiration..). Instead, if you're removing elements relative to other elements (where, you need to remove the next element) then you should use a linked list.
There is no simple answer to this:
It depends on what you are optimizing for. Do you care more about the time taken to perform the operations, or the space used by the lists?
It depends on how long the lists are.
It depends on the proportion of elements that you are removing from the lists.
It depends on the other things that you do to the list.
The chances are that one or more of these determining factors is not predictable up-front; i.e. you don't really know. So my advice would be to put this off for now; i.e. just pick one or the other based on gut feeling (or a coin toss). You can revisit the decision later, if you have a quantifiable performance problem in this area ... as demonstrated by cpu or memory usage profiling.

Seeking further understanding on Iterators in java

If I am using a for loop (the standard for loop, not an enhanced for statement), I fail to see how an iterator increases efficiency when searching through a collection. If I have a statement such as:
(Assuming that aList is a List of generic objects, type E, nextElement refers to the next element within the list)
for (int index = 0; index < aList.size(); index++){
E nextElement = aList.get(index);
// do something with nextElement...
}
and I have the get method that looks something like:
Node<E> nodeRef = head;
for (int i = 0; i < index; i++){
nodeRef = nodeRef.next;
// possible other code
}
this would essentially be searching through the List, one element at a time. However, if I use an iterator, will it not be doing the same operation? I know an iterator is supposed to be O(1) speed, but wouldn't it be O(n) if it has to search through the entire list anyway?
It's not primarily about efficiency, IMO. It's about abstraction. Using an index ties you to collections which can retrieve an item for a given index efficiently (so it won't work well with a linked list, say)... and it doesn't express what you're trying to do, which is iterate over the list.
With an iterator, you can express the idea of iterating over a sequence of items whether that sequence can easily be indexed or not, whether the size is known in advance or not, and even in cases where it's effectively infinite.
Your second case is still written using a for loop which increments an index, which isn't the idiomatic way of thinking about it - it should simply be testing whether or not it's reached the end. For example, it might be:
for (Node<E> nodeRef = head; nodeRef != null; nodeRef = nodeRef.next)
{
}
Now we have the right abstraction: the loop expresses where we start (the head), when we stop (when there are no more elements) and how we go from one element to the next (using the next field). This expresses the idea of iterating more effectively than "I've got a counter starting at 0, and I'm going to ask for the value at the particular counter on each iteration until the value of the counter is greater than some value which happens to be the length of the list."
We're fairly used to the latter way of expressing things, but it doesn't really say what we mean nearly as may as the iterator approach.
Iterators are not about increasing efficiency, they're about abstraction in the object-oriented sense. Implementation-wise, the iterator is doing something similar to what you're doing, going through your collection one element at a time, at least if the collection is index-based. It's supposed to be O(1) when retrieving the next element, not the entire list. Iterators help mask what collection is underneath as well, it could be a linked list or a set, etc, but you don't have to know.
Also, notice how connected your for loop is to your specific logic that you want to do on each element, while with an iterator you can abstract out the looping logic from whatever action you want to do.
I think the question you are asking refers to the efficiency of iterators vs. a for-loop using an explicit get on the collection object.
If you write code with a naive version of get, and you iterate through your list using it, then it takes you
one step to "get" the first element
two steps to "get" the second
three steps to get the third
...
n steps to get the last
for a total of n(n-1)/2 operations, which is O(n^2).
But if you used an iterator which internally kept track of the next element (i.e. one step to advance), then iterating the whole list is O(n), a big improvement.
Like Jon said, iterators have nothing to do with efficiency they just abstract the concept of being able to iterate over a collection. So you are right, if you are just searching through a list there is no real benefit to an iterator over a for loop, but in some cases iterators provide convenient ways for doing things that would be difficult with a simple for loop. For example:
while(itr.hasNext()) {
if(itr.next().equals(somethingBad);
itr.remove();
}
In other cases iterators provide a way to traverse the elements of a collection, that you can not fetch by index (eg a hashset). In this case a for loop is not an option.
Remember that it's also a Design Pattern.
"The Iterator Pattern allows traversal of the elements of an aggregate without exposing the underlying implementation. It also places the task of traversal on the iterator object, not on the aggregate, which simplifies the aggregate interface and implementation, and places the responsibility where it should be." (From: Head First Design Pattern)
It's about encapsulation and also the 'single responsibility' principle.
Cheers,
Wim
You are using a linked list here. Iterating over that list without an iterator takes O(n^2) steps, where n is the size of the list. O(n) for iterating over the list and O(n) each time for finding the next element.
The iterator, on the other hand, remembers the node it has visited the last time, and therefore needs only O(1) to find the next element. So eventually the complexity is O(n), which is faster.

Categories

Resources