Creating a sorted linked list class - java

I'm trying to create a SortedLinkedList class which extends LinkedList. This class is supposed to add items to a SortedLinkedList and have them sorted.
I'm trying to override the boolean add(E obj) method in order to add items in sorted order.
On a Stackoverflow question I found the following method of overriding add(E obj):
public boolean add(E obj) {
int index = 0;
for( ; index<size() ; index++){
E object= get(index);
if(obj.compareTo(object) < 0){
break;
}
}
add(index, obj);
return true;
};
I understand how this method works, however I've read that using a ListIterator would be more efficient than using get(index). I've been trying to use a ListIterator but I can't seem to get everything to work correctly.
This is how far I got with using the Listiterator, I'm sure there is something wrong with it but I can't seem to figure it out:
public boolean add(E obj)
{
add(size(), obj);
ListIterator<E> iterator = listIterator();
while(iterator.hasNext())
{
E object = iterator.next();
if(obj.compareTo(object)<0)
{
//do something;
}
}
return true;
}
Any advice on how I can sort the list using the iterator?

Don't think about sorting the list using the iterator. Think about inserting a new element into an already-sorted list using the iterator.
Your list will start off empty. When you add the first element, you will have a list of one element, which is, by definition, sorted. If you make sure that you always add subsequent elements in the right place, then the list will stay sorted!
This is exactly what the code that uses get does, but as you quite rightly say, that is not efficient for linked lists. What you need to do is reproduce that algorithm using the iterator.
Hint: a list iterator lets you add an element at the current position.

Related

Why need to judge the element if or not exsit in a collection in removeAll(Collection c)?

could you help me understand this snippet? I don't understand why this function have to check the collection contains the element before remove it. Since the iterator is from the collection, all element returned by iterator is definitely in collection.So I think it's a waste of time. Thank you a lot
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
if (c.contains(it.next())) {//I don't understand
it.remove();
modified = true;
}
}
return modified;
}
This looks like an implementation of Set's removeAll.
The iterator is not iterating on the Collection passed to the method. It is iterating on the Set on which the method was called.
set1.removeAll(collection2);
You are iterating over the elements of set1 and check for each one of them whether it belongs to collection2 before removing it from the Set.
That snippet is from a class that implements Collection. The method only removes items from the local class instance (through the local iterator()) when the Collection c also contains an item that is equals.

How to Remove Value from List<SelectItem>

How to remove value of "abcd" from List<SelectItem>.
public class Sample {
public static void main(String[] args) {
List<SelectItem> list= new ArrayList<SelectItem>();
list.add(new SelectItem("abc"));
list.add(new SelectItem("abcd"));
list.add(new SelectItem("abcdf"));
System.out.println("size :"+list.size());
System.out.println("List :"+list);
list.remove(new SelectItem("abcd"));
System.out.println("List :"+list.size());
}
}
try this instead:
list.remove(1);
Where 1 is the index. This removes the element at the specified position in this list.
If you want to remove the element based on its state like this :
list.remove(new SelectItem("abcd"));
You have to override the .equals() and also .hashCode() methods of the SelectItem class because :
remove(Object o) internally uses the .equals() to compare if the element exist in the list, if it does, It removes the first occurrence of new SelectItem("abcd")
It seems that SelectItem doesn't implement equals(). The only option I can see is to iterate over each element and determine the index, then use ArrayList#remove(int index).
It appears that SelectItem isn't implementing the equals & hashCode method properly. In such a scenario, you can either iterate over the list and delete the appropriate item, or keep a reference to the actual select items and remove that reference directly.
You need to use an Iterator and traverse over your list. Whenever you find a match(I think you can use the getValue() method of SelectItem), use the iterator to remove it.
Since you can't change the equals() method of SelectItem, use the iterator like this
Iterator<SelectItem> itr = list.iterator();
while (itr.hasNext()) {
SelectItem si = itr.next();
if (si.getValue().equals("abcd")) {
itr.remove();
// You removed what you wanted, you can break here, if you want
}
}
Use this:
SelectItem selectItem = new SelectItem();
selectItem.setValue("abcd");
list.remove(selectItem); // Just call the remove method
// If present, it'll remove it, else, won't do anything
In the context of JSF, a SelectItem is a valid option in a UISelectOne, when you use the constructor that takes only a argument, the parameters is set as it Value.
Try this code:
public SelectItem getItem(List<SelectItem> items, Object value) {
for (SelectItem si : items) {
if (si.getValue().equals(si)) {
return si;
}
}
return null;
}
And use like this:
list.remove(getItemToRemove(list, "abcd");
This dont modify the list when iterates, it return the desired element, and after you can remove it or use as you want
Cheers
In order for the code you wrote to work you need to implement the equals() method of SelectItem.
From the java doc of remove method:
removes the element with the lowest index i such
that (o==null ? get(i)==null : o.equals(get(i)))
Notice the part o.equals(get(i)) in the condition that was provided.
In other words - the implementation of ArrayList searches for the specific object to remove. How can it tell if a certain item is the requested object? Naturally, it uses the equals() method and if the item is equal to the item-to-remove you provided, only then it's removed.
Please note: In order to remain consistent with other collection operations, you also need to implement the hashCode() method such that it is consistent with the equals() method.
Try this code,
public SelectItem getItemToRemove(List<SelectItem> items, SelectItem item) {
for (SelectItem si : items) {
if (si.getValue().equals(item.getValue())) {
return si;
}
}
return null;
}
Try this logic,
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getValue().toString().equals("abcd")) {
list.remove(i);
System.out.println(i); //checking the element number which got removed
}
}

Reverse Ordered list using Previous Iterator

I want to start at the end of the list and iterate it using ListIterators previous method
public void add(E obj) {
ListIterator <E> iter = theList.listIterator();
while (iter.hasNext()) {
if (obj.compareTo(iter.next()) < 0) {
iter.previous();
iter.add(obj);
return;
}
}
iter.add(obj);
}
Every time I run my test class it iterators from the beginning.
to get iterator in reverse order use method list.listIterator(int index)
this method will return iterator from specified position,
you should put size of list means last element index.
after that you can use hasPrevious() and previous() method.
this will work,
// declare arraylist
ArrayList<...> a = new ArrayList<...>();
// Add elements to list.
// Generate an iterator. Start just after the last element.
ListIterator li = a.listIterator(a.size());
// Iterate in reverse.
while(li.hasPrevious()) {
System.out.println(li.previous());
}
ListIterator, like all Iterators, always start at the beginning. The previous method allows for less constrained movement, but it still starts at the beginning. You overall intent is unclear, so it's possible you're coming at this the wrong way, but the most straightforward way for you would be to reorder the list first and then do your iteration.
UPDATE Nevermind, Rajj has it.

Can I subclass "standard" arraylist iterator?

I need to iterate all the elements of ArrayList except the last one. So I want to create such iterator. But I don't what to implement the whole iterator, I need to override only the hasNext() method, so I would like to subclass a "standard" iterator. Is there any way to do that?
I think the better way to do that rather than overriding the default iterator is to iterate the ArrayList on your own. An ArrayListhas a couple of method defined that can help you accomplish the task: get(int) and size().
Everything you have to do is to get the total number of elements in the ArrayList(with size()) and then loop through the elements accessing each element directly in each iteration using the get() method. Your code would look something like this:
for(int i = 0; i < myList.size() - 1; i++){
element = myList.get(i);
//do something
}
Now with this principle in mind, you may create your own class to iterate the ArrayList.
It would be odd to modify the iterator to perform this traversal. The obvious thing to do is to write the "algorithm" as you want it:
public static <T> void eachExceptLast(List<? extends T> list, Operation<T> op) {
Iterator<T> iter = list.iterator();
if (!iter.hasNext()) {
return;
}
T item = iter.next();
while (iter.hasNext()) {
op.run(item);
item = iter.next();
}
}
(Or use an index assuming a RandomAccess list.)
However, there's a much better way of doing this. list.subList(0, list.size()-1) (for a non-empty list) will return a view of the original list less the last element. It doesn't do a copy, and you can even use Iterator.remove.
You can create a class that implements either the Iterator or ListIterator interfaces and then override the hasNext() method .

Iterator has .next() - is there a way to get the previous element instead of the next one?

I have an Iterator that I use on a HashMap, and I save and load the iterator.
is there a way to get the previous key in the HashMap with Iterator? (java.util.Iterator)
Update
I save it as an attribute in a Red5 connection and then load it back to continue working where i stopped.
Another update
I'm iterating through the keyset of the HashMap
You can use ListIterator instead of Iterator.
ListIterator has previous() and hasPrevious() methods.
Not directly, as others pointed out, but if you e.g. need to access one previous element you could easily save that in a separate variable.
T previous = null;
for (Iterator<T> i = map.keySet().iterator(); i.hasNext();) {
T element = i.next();
// Do something with "element" and "previous" (if not null)
previous = element;
}
It sounds like you want the array semantics more akin to a ListIterator rather than those provided by the Iterator interface. The easiest way to acquire such a thing is likely to construct a list ( from the key-set (LinkedList<K> keyList = new LinkedList<K>(map.keySet())), then use a ListIterator manually instead of a regular Iterator or foreach.
For very simple cases of needing to remember consecutive items, the simplest way to handle this is to store the previous Key in a local variable and update it at the end of the loop.
No, an Iterator<E> defines only 3 methods:
boolean hasNext()
E next()
void remove()
You can of course implement your own iterator.
As others have said, you only access an element using next(). However it's sort of a matter of terminology. Once you call next() this is the current element.
Unless the problem is you need to see two consecutive items in the collection each iteration, in which case a simple variable would seem easiest.
Although Set doesn't provide a method for a reverse iterator, Deque does. You can use descendingIterator() for an iterator in reverse order and iterator(), for an iterator in forwards order.
(You can create a Deque from a Set via Deque<T> deque = new LinkedList<T>(set), where set is your Set and T the generic type you're using.)
Ultimately Iterators are not fully suited for your task.
Why not create a List from your Set (via, eg, List list = new LinkedList(set)) and iterate by using a standard indexed for-loop? That way you know the previous element is at i - 1.
using iterator, No you dont have an option to get a previous key value. it has only hasNext() and next() methods.
No, you can't. The Iterator interface has no method to get the previous element.
But what you can do is - a little bit rubbish- creating a List<Entry<Integer, YourObjectType>> where the Integer-value represents the hash-code of the key-object. Then you can do something like this:
for (int i = 0; i < list.size(); i++)
{
YourObjectType current = list.get(i).getValue();
YourObjectType previous = (i == 0 ? null : list.get(i - 1).getValue());
// Do whatever you want
}
I know this is very rubbish, but it is possible
Make your own Iterator:
public class EnhancedIterator<E> implements Iterator<E>{
private List<E> list;
private int indexSelected=-1;
public EnhancedIterator(List<E> list){
this.list=list;
}
#Override
public boolean hasNext() {
return indexSelected<list.size()-1;
}
#Override
public E next() {
indexSelected++;
return current();
}
#Override
public void remove() {
list.remove(indexSelected);
}
public void remove(int i){
list.remove(i);
if(i<indexSelected){
indexSelected--;
}
}
public E previous(){
indexSelected--;
return current();
}
public E current(){
return list.get(indexSelected);
}
public E get(int i){
return list.get(i);
}
}

Categories