remove item from comparable array - java

I'm very new to java and my first question is what is this Comparable thing? and in my sample code, why Class Bag<T extends Comparable<T>>?? What's the purpose?
My second question is how to remove an item from this Comparable array. I have wrote the removeMin method, I have found the item, I named the variable "min", how do I go on and remove this min item from the arrayList? Thanks a lot!
Here's some partial code:
public class Bag<T extends Comparable<T>> implements Iterable<T> {
private int MAX_ITEMS = 10; // initial array size
private int size;
private Comparable[] data;
public Bag( ) {
//data = (Comparable []) new Object[MAX_ITEMS];
data = (T []) new Comparable[MAX_ITEMS];
size = 0;
}
public Comparable removeMin(){
Iterator<T> iterator=iterator();
T min = iterator.next();
while (iterator.hasNext())
{
T next = iterator.next();
if (min.compareTo(next) > 0)
min = next;
****************************************************
How to remove this min item?
****************************************************
}
return min;
}

What is this Comparable thing?
It is a generic interface that can be implemented by classes whose instances you need to be able to compare with each other. Comparable<T> has a single method int compareTo<other T>. The implementation of the method is supposed to compare this with the other instance
In my sample code, why class Bag<T extends Comparable<T>>? What's the purpose?
This is saying that your Bag class is a generic class with a type parameter T. The T extends Comparable<T> bits is saying that T must be some class that implements Comparable<T>.
My second question is how to remove an item from this Comparable array.
That is for you to figure out, based on your knowledge of how arrays work. The big constraint you have to deal with is that an array's size cannot be changed, so there is no magical operation that will simply remove something from the middle of the array.
There are two approaches:
Create a new array containing just the elements that you don't want to be removed. (Hint: copy them)
Move the elements around in the existing array to "fill the hole" left when you conceptually remove an element. (Hint: notice the size field. What is it there for?)
Assuming that you wrote the removeMin method from scratch, I think you have gone down a blind alley with trying to use an iterator there1. Try coding it to operate directly on the data array.
The removeMin problem has two parts:
Find the index in data for the smallest element
Remove the element at that index
Hint: the first part requires that you look at every element ... and this has to be done before you do the removal. This should be reflected in your code.
1 - If you were using an ArrayList<T> or similar, then using data.iterator() would be a reasonable choice. The problem is that arrays don't directly support the Iterable API.
Now if you are required to make your Bag class implement Iterable<T>, then you could use the iteration mechanism you implemented for that purpose in your removeMin method. But even there, the API is not ideal for the purpose. You would still need to iterate the collection twice. Once to find the smallest element, and a second time to remove it. And removal via an iterator means that the iterator would need to implement the optional Iterator.remove() method .... which brings you back full circle.

It is the java.lang.Comparable interface. <T extends Comparable<T>> is a generic type, at compile time Java will require that an instance provide an implementation of int compareTo(T o) which (from the Javadoc) returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object. Also, you might back your Bag with a Collection (instead of an array), like
class Bag<T extends Comparable<T>> implements Iterable<T> {
private List<T> al = new ArrayList<>();
public Bag() {
super();
}
public T removeMin() {
Iterator<T> iterator = iterator();
T min = iterator.hasNext() ? iterator.next() : null;
while (iterator.hasNext()) {
T next = iterator.next();
if (min.compareTo(next) > 0) {
min = next;
}
}
if (min != null) {
iterator = iterator();
while (iterator.hasNext()) {
T next = iterator.next();
if (min.compareTo(next) == 0) {
iterator.remove();
break;
}
}
}
return min;
}
#Override
public Iterator<T> iterator() {
return al.iterator();
}
}
Note that Iterator.remove() says (in part) the behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method.

The comparable interface is implemented in order to define a comparison mechanism to your custom types.
array are usually size fixed so you cannot just remove an item without copying the remaining ones to a new array. I suggest to change your array to dynamic list:
public class Bag<T extends Comparable<T>> implements Iterable<T> {
private int size;
private LinkedList<T> data;
public Bag() {
data = new LinkedList<T>();
size = 0;
}
public Comparable removeMin() {
Iterator<T> iterator = iterator();
T min = iterator.next();
while (iterator.hasNext()) {
T next = iterator.next();
if (min.compareTo(next) > 0)
min = next;
data.remove(min);
}
return min;
}
}

what is this Comparable thing
In simplest term it specifies how the items can be compared to each other . For example in your case your class Bag may contain any item so you used generic type T but you want your items to be comparable to each other too, so you used T extends Comparable<T>
The Comparable interface has a method compareTo which is used to compare the items. You can read more about it in JLS.
Now you may be wondering why do I need to compare items?
Imagine if you have no way to compare then how can you say 5 is a bigger number than 1 or why A comes before B in alphabets. They do so because we have some order for them and based on them we can compare then. Similarly you may like a items in your bag to be comparable.
how to remove an item from this Comparable array
To iterate over the items you already seem to use an iterator
Iterator<T> iterator=iterator();
T min = iterator.next();
You can use same iterator to remove the item if it matches your condition. So your code should be iterator.remove(). But you should also ensure for null check and existence check at all relevant places

Related

best way to Iterate over a collection and array consecutively

Its a very trivial question and related to coding Style and I am just asking to make my coding style more readable
Suppose I have a Collection like linkedList and an Array and I need to iterate over both simultaneously.
currently the best way I know is to get a iterator over list and define a index variable outside the iterator loop and increment the index variable simultaneously to access both next elements {list and array}. Please refer the example below
LinkedList<Integer> list = new LinkedList<Integer>();
Integer[] arr = new Array[25];
// lets suppose both have 25 elements.
// My Iteration method will be
int index =0;
for (Integer val : list) {
System.out.println(val);
System.out.println(arr[index++]);
}
so is it the only way or is there any other way I can perform this iteration in more readable and more relatable manner, where I don't have to take index variable separately.
I know it can be possible that array might have less or more elements than collection but I am only talking about the cases where they have equal and we need to iterate over Both of them.
PS : anybody can write a code that a computer can understand, actual challenge is to write code which humans can understand easily.
What you have is essentially fine: it's simple, and simple can be sufficient to make code readable.
The only thing I would caution about is the side effect of index++ inside arr[index++]: if, say, you want to use the same value multiple times in the loop body, you couldn't simply copy+paste.
Consider pulling out a variable as the first thing in the loop to store the "current" array element (which is essentially what the enhanced for loop does for the list element).
for (Integer val : list) {
Integer fromArr = arr[index++];
// ...
}
Just to point out an alternative without having a separate variable for the index, you can use ListIterator, which provides you with the index of the element.
// Assuming list and are have same number of elements.
for (ListIterator<Integer> it = list.listIterator();
it.hasNext();) {
// The ordering of these statements is important, because next() changes nextIndex().
Integer fromArr = arr[it.nextIndex()];
Integer val = it.next();
// ...
}
ListIterator is not an especially widely-used class, though; its use may in and of itself be confusing.
One of the downsides of the ListIterator approach is that you have to use the it correctly: you shouldn't touch it inside the loop (after getting the values), you have to put the statements in the right order, etc.
Another approach would be to create a library method analogous to Python's enumerate:
static <T> Iterable<Map.Entry<Integer, T>> enumerate(Iterable<? extends T> iterable) {
return () -> new Iterator<T>() {
int index = 0;
Iterator<? extends T> delegate = iterable.iterator();
#Override public boolean hasNext() { return delegate.hasNext(); }
#Override public Map.Entry<Integer, T> next() {
return new AbstractMap.SimpleEntry<>(index++, delegate.next());
}
};
}
This returns an iterable of map entries, where the key is the index and the value is the corresponding value.
You could then use this in an enhanced for loop:
for (Map.Entry<Integer, Integer> entry : enumerate(list)) {
Integer fromList = entry.getValue();
Integer fromArr = arr[entry.getKey()];
}
One option is to have 2 iterators, but I don't think it is any clearer:
for (Iterator<Integer> i1 = list.iterator(), i2 = Arrays.asList(arr).iterator();
i1.hasNext() && i2.hasNext();) {
System.out.println(i1.next());
System.out.println(i2.next());
}
But it is more robust in that it finishes at the shorter of the 2 collections.
I tried to simplify and handle size wise collections where both need not be of the same size. I believe this would work even if the sizes are not same and just one loop would suffice. Code snippet below:
LinkedList<Integer> list = new LinkedList<Integer>();
Integer[] arr = new Array[25];
int maxLength= Math.max(list.size(),arr.size());
//Looping over the lengthy collection( could be Linkedlist or arraylist)
for(int i=0;i<maxLength;i++){
if(list.size()>i)
System.out.println(list[i]);
if(arr.size()>i)
System.out.println(arr[i]);
}
Hope this helps! Thanks

How to get an element in specific position in most efficient way in Iterable<T>?

I need to get an element in a specific position in Iterable<MyType> in order not to loop through all elements of Iterable<MyType> because I know at which position the desired element is located(As far as I am concerned looping through all elements would take O(n) time, on the other hand accessing specific one would take O(1) time).
This has to be an element before the last one.
But I can't find a way to do just that.
public interface Iterable<T>, apparently, doesn't have methods to access an element at an arbitrary position.
I tried casting Iterable<MyType> to List<MyType> but the casting failed in runtime with ClassCastException. So I can't use ListIterator<E>, simple List.get(E e) or some custom Function<T, U> in order to traverse elements backwards or to get this very element(these things I intended to do).
My current code
// list.getItems() returns Iterable<MyType>
// I know that element I am looking for is at (iterable.size - 2) position
for(MyType item : list.getItems()) {
if (item.convertToText().matches(targetElementRegex)) {
Pattern pattern = Pattern.compile(targetElementRegex);
Matcher matcher = pattern.matcher(item.convertToText());
if (matcher.find()) {
return Optional.of(Integer.parseInt(matcher.group(1)));
}
}
}
As you can see currently I am just looping through all elements in Iterable<T> until I get to target element although I do know in which position target element I am looking for is at.
I want to get an element at a specific position in Iterable<MyType>.
I want to find out the most efficient way to do just that(or at least the one which is better than my current solution).
UPD: list is an instance of a class from a third-party library, I didn't write getItems() neither I can add something new in list class.
Iterable does not give you a way to extract element on given position, and it's by design. Collections framework contains more specialized classes to handle sequential collections with O(1) element access. Those are various well-known list implementations, especially those implementing RandomAccess interface.
As you see, choosing a collection interface can make big difference especially when it comes to O(xxx) notation things. That's kind of trade-off between versatility and performance. Universal interface like Iterable provides you widest set of applicable inputs, but you gain performance only for RandomAccess collections.
If all the inputs you are going to consume are RandomAccess collections (ArrayList implements it) there is no reason to handle them as Iterable. If it's not the case, you can check this condition on runtime and choose most efficient algorithm.
With the Iterable interface you cant get an element at a specific index. All the interface allows you is to to go trough all the items in an Iterable and observe whats there but thats all. You will have to manually manage the current position(index/cursor). A simple solution would be as follows:
public static <T> T retrieveItemByIndex(Iterable<T> iterable, int index) {
if (iterable == null || index < 0) {
return null;
}
int cursor = 0;
Iterator<T> iterator = iterable.iterator();
while (cursor < index && iterator.hasNext()) {
iterator.next();
cursor++;
}
return cursor == index && iterator.hasNext() ? iterator.next() : null;
}
If you don't want this helper method to use generics simply alter it to work with only your custom type as:
public MyType retrieveItemByIndex(Iterable<MyType> iterable, int index) {
if (iterable == null || index < 0) {
return null;
}
int cursor = 0;
Iterator<MyType> iterator = iterable.iterator();
while (cursor < index && iterator.hasNext()) {
iterator.next();
cursor++;
}
return cursor == index && iterator.hasNext() ? iterator.next() : null;
}
Another approach would be to use the Stream API (Java 8 and above).
First you will have to get a stream out of your Iterable then skip the first index elements and find the first. If the index is out of bounds a default value will be returned.
int index = N - 2;
MyType defaultValue = null;
StreamSupport.stream(iterable.spliterator(), false)
.skip(index)
.findFirst()
.orElse(defaultValue);
As mentioned by dbl, you cannot get an element at a specific index for Iterable object.
If you plan to convert the Iterable object to list, that's just the same time(O(n)) spent, plus O(1) to get the target element.
If you're really concerned of your O(n) time, I suggest you just iterate it as is until your target element (O(n-1)).
Why dont you just index that position with the list before you enter the loop if you just want the 2nd to last position? Instead of list.getItems(), try list.getItem(list.getItemCount()-2)

How to iterate through two generic lists with different types one item after another in java?

I want to create an iterator class which allows me to iterate through lists with generic types (e.g. lst1 integer, lst2 string) one item after another.
For this I have to consider the following given situation.
The interface is a generic Iterator. This part of the code cannot be modified.
interface Iterator<E> {
E next ();
boolean hasNext();
}
The list class is also defined as following. The most important, a list object can return a iterator object with the method getIterator(). This part of the code cannot be modified.
class List<T> {
class ListNode {
T val;
ListNode next;
ListNode (T v) {
val = v; next = null;
}
}
ListNode head;
List (ListNode hd) { head = hd; }
List () { this(null); }
void prepend (T val) {
ListNode p = new ListNode(val);
p.next = head;
head = p;
}
//some other methods
class ListIterator implements Iterator<T> {
ListNode pos;
ListIterator () {
pos = head;
}
public T next () {
T res = pos.val;
pos = pos.next;
return res;
}
public boolean hasNext () {
return pos != null;
}
}
Iterator<T> getIterator () {
return this.new ListIterator();
}
}
Lets assume both list have the same type and for now they have also the same length. I tried to create a class with two iterator objects and used the methods of the iterator objects to implement the interface Iterator. This part of the code is created by me and can be modified.
class ZipIterator<T> implements Iterator<T>
{
int counter;
Iterator<T> first;
Iterator<T> second;
ZipIterator (Iterator<T> f, Iterator<T> s)
{
first = f;
second = s;
counter = 0;
}
public T next ()
{
if (counter % 2 == 0)
{
counter++;
return first.next();
}
else
{
counter++;
return second.next();
}
}
public boolean hasNext ()
{
if (counter % 2 == 0)
return first.hasNext();
else
return second.hasNext();
}
}
This works fine for two list with the same type. Here is the code and the output I used for the test:
class IteratorUtils
{
public static void main (String[] args)
{
List<Integer> lst1 = new List<>();
List<Integer> lst2 = new List<>();
lst1.prepend(3);
lst1.prepend(2);
lst1.prepend(1);
lst2.prepend(8);
lst2.prepend(9);
lst2.prepend(10);
Iterator<Integer> it1 = lst1.getIterator();
Iterator<Integer> it2 = lst2.getIterator();
ZipIterator<Integer> zit = new ZipIterator<>(it1, it2);
while (zit.hasNext())
{
System.out.println(zit.next());
}
}
}
Output:
1
10
2
9
3
8
Now I want to implement the ZipIterator in a generic way, so I can use two lists with different types of items (e.g. integer and string). I know I have to change the class ZipIterator so the method next() returns a generic type but I don't know how.
This is a university task i have to do and the prof has left a hint "use wild cards like: ? extends T, ? super T, ? extends Object". But with the wild cards i can only specify the types in or against the inherits direction, right? Is this possible to change the ZipIterator class that way so it accepts two iterator objects with different types?
I won't give the full solution (and judging by your effort you don't want it), but I will attempt to explain in a way that will let you find it yourself.
First of all an unrelated note: you're specifying a specific iteration order. I assume this is fine and I will not touch it.
Your professor gave you the hint of using bounded generics. Let's understand why they are needed (see also the tutorial here and/or here). If you were asked to write a single method that takes an argument of any of 2 unknown types, your solution would be to find and take their common superclass - Object.
In generics the situation is similar - find the most common denominator, only the syntax is a bit more tricky. If you were to write the constructor
ZipIterator(Iterator<Object> f, Iterator<Object> s) {...}
and attempt the initialization
List<Integer> lst1 = new List<>();
List<String> lst2 = new List<>();
new ZipIterator(it1, it2);
you would get a compilation error (read it). That is because a List<String> is not a List<Object>, even though a String is an Object. The correct way to do this is
ZipIterator(Iterator<? extends Object> f, Iterator<? extends Object> s) {...}
where ? extends Object means "any type that extends Object" (which is all of them because Object...).
So you have the constructor, and you would need to make changes to your class in order to accommodate it. You don't even need to implement the given Iterator<E>, you just hold 2 of those like you already do. Lastly, the class itself need not have a generic type: since its next method must be able to return any type, it always returns Object.
If you have any questions during your future attempts at this problem, or you find that this solution doesn't fit the assignment's requirements, feel free to post a comment.
I know I have to change the class ZipIterator so the method next() returns a generic type but I don't know how.
That's not quite right. Since ZipIterator<T> extends Iterator<T>, it's actually set in stone that its next() method must return T. And this makes sense: the whole point of the iterator's type parameter is to let you specify the type that its next() method will return.
Instead, all your professor wants is for it to be possible to construct a ZipIterator<...> from two iterators with different type arguments. For example, (s)he wants to be able to write:
List<Integer> listOfIntegers = ...;
List<String> listOfStrings = ...;
ZipIterator<Object> zipIterator =
new ZipIterator<>(listOfIntegers.getIterator(), listOfStrings.getIterator());
Note that, since zipIterator.next() will sometimes return an Integer and sometimes a String, we had to go with something like ZipIterator<Object> that allows for both possibilities. Other options included ZipIterator<Serializable> or ZipIterator<Comparable<?>>, since Integer-s and String-s are both Serializable and both Comparable<?>.
So the problem that your professor wants you to solve is that in your current code, your constructor requires both iterators to have the exact same type argument (as each other, and as the ZipIterator itself):
ZipIterator (Iterator<T> f, Iterator<T> s)
Do you see how to fix that?
as i understand you want to iterate over list of different types one of solution is to make your constructor accepted iterator fulfill the requirement that it being iterator of any thing that extends object but this will limits your use of the retrieved items to just use it as objects or you will have to cast them to achieve further tasks a less restrictive approach is to make the constructor accepted iterator fulfill the requirement that it being iterator of any thing that extends the nearest common ancestor like this ZipIterator(Iterator<? extends T> f, Iterator<? extends T> s) so your class will look like this
class ZipIterator<T> implements Iterator<T> {
int counter;
Iterator<? extends T> first;
Iterator<? extends T> second;
ZipIterator(Iterator<? extends T> f, Iterator<? extends T> s) {
first = f;
second = s;
counter = 0;
}
#Override
public T next() {
if (counter % 2 == 0) {
counter++;
return first.next();
} else {
counter++;
return second.next();
}
}
#Override
public boolean hasNext() {
if (counter % 2 == 0) {
return first.hasNext();
} else {
return second.hasNext();
}
}
}
then to use it you can specify the best appropriate super class that both types converge to it, in cases of it is Object you can write ZipIterator<Object> zit = ,the following code will show you an arbitrary use case
List<StringBuilder> bl= Arrays.asList(new StringBuilder("hi i'm builder"));
List<String> sl = Arrays.asList("hi i'm string");
ZipIterator<CharSequence> zit = new ZipIterator<>(bl.iterator(), sl.iterator());
while (zit.hasNext()) {
CharSequence cs = zit.next();
System.out.println(cs.subSequence(6,cs.length()));
}
Thanks for the help. I have learned a lot. Here comes my solution and some more explanations to the task.
Please notice first, that the design of the ZipIterator class is not set in stone. ZipIterator was designed by me. There may be another solution but this was my attempt.
To specify the task: "Please construct a class IteratorUtils with several methods. The method zip receives two iterator objects and returns one iterator object, which iterates alternating through the items of the two received iterator objects. The iterator returned by the zip function should stop after the last item of the shorter iterator object. Use wildcards so you can apply the zip function to diffrent types of iterator objects."
For this I first created the class IteratorUtils. Please notice that the design of the zip function is also not set in stone. In the task it only says: "The method zip receives two iterator objects and returns one iterator object, which iterates alternating through the items of the two received iterator objects."
class IteratorUtils
{
static ZipIterator zip (Iterator<? extends Object> first, Iterator<? extends Object> second)
{
return new ZipIterator(first, second);
}
}
Then I created the class ZipIterator. After reading through your answers and some tutorials I understood the meaning of bounded type parameters in this task. Like user1803551 said, the ZipIterator class should not be generic. I just had to realize that I hat to find the common superclass (here Object). So I had to change my ZipIterator class to the following:
class ZipIterator
{
int counter;
Iterator first;
Iterator second;
ZipIterator (Iterator<? extends Object> f, Iterator<? extends Object> s)
{
first = f;
second = s;
counter = 0;
}
public Object next ()
{
if (counter % 2 == 0)
{
counter++;
return first.next();
}
else
{
counter++;
return second.next();
}
}
public boolean hasNext ()
{
if (counter % 2 == 0)
return first.hasNext();
else
return second.hasNext();
}
}
In my main method I use the following code:
public static void main (String[] args)
{
List<Integer> lst1 = new List<>();
List<String> lst2 = new List<>();
lst1.prepend(3);
lst1.prepend(2);
lst1.prepend(1);
lst2.prepend("three");
lst2.prepend("two");
lst2.prepend("one");
Iterator<Integer> it1 = lst1.getIterator();
Iterator<String> it2 = lst2.getIterator();
ZipIterator zit = zip(it1, it2);
while (zit.hasNext())
{
System.out.println(zit.next());
}
}
Output:
1
one
2
two
3
three

Java Generic formal parameters

I am implementing a simple LinkedList class and I want it to use generics. The class declaration is:
public class LinkedList<E> extends AbstractList<E> implements List<E> {
This is a teaching example, so the Abstract parent and the interface are also my own. The problem arises when I realized that to add and maintain sorting, I need a class (E) which is also Comparable. I thought I could limit that to just the methods where it actually makes a difference. But based on the comments below, that may be my basic misunderstanding.
Here's the code:
public void addSorted(<E extends Comparable<E>> value) {
if (front == null || value.compareTo(front.word) <= 0) {
// insert at front of list
front = new ListNode<E>(value, front);
} else {
// insert in middle of list
ListNode<E> current = front;
while (current.next != null && current.next.word.compareTo(value) < 0) {
current = current.next;
}
current.next = new ListNode<E>(value, current.next);
}
}
It seemed to me that if I never want to call addSorted then why should the particular class be limited to E's that implement Comparable? Or is there a totally different way to do it, with a generic analog to instances?
Consider what happens if you are able to call both add and addSorted on a LinkedList instance:
LinkedList<String> list = new LinkedList<>();
list.add("c"); list.add("a");
list.addSorted("b");
In this case, where do you expect "b" to be inserted into a list ["c", "a"]:
It is lexicographically before "c", so it could be inserted at the start, yielding ["b", "c", "a"];
It is lexicographically after "a", so it could be inserted at the end, yielding ["c", "a", "b"];
But neither list is really "sorted" afterwards.
To me, the only obvious way to resolve this ambiguity is to force all adds to be done in a sorted way. This implies that you should create a subclass of LinkedList, SortedLinkedList, which overrides the LinkedList.add method:
class SortedLinkedList<E extends Comparable<E>> extends LinkedList<E> {
void add(E element) {
// The implementation of addSorted.
}
}
In general, the way I would handle methods that should only available for certain generic types is to do it using a method which accepts an instance of the class as the first parameter, outside the definition of the class (or inside the definition of the class, but defined as static). This means that it's not part of the interface of the class, so it's not present for classes with incompatible generic types.
For example, if you wanted to add a sort method to sort LinkedLists, this is obviously only sensible for ones with Comparable elements:
static <E extends Comparable<E>> void sort(LinkedList<E> list) {
// ...
}
For example:
LinkedList<String> strList = new LinkedList<>();
// ... Add elements.
sort(strList); // OK.
LinkedList<Object> objList = new LinkedList<>();
// ... Add elements.
sort(objList); // Compiler error - Object is not a valid bound.

Inserting into Sorted LinkedList Java

I have this code below where I am inserting a new integer into a sorted LinkedList of ints but I do not think it is the "correct" way of doing things as I know there are singly linkedlist with pointer to the next value and doubly linkedlist with pointers to the next and previous value. I tried to use Nodes to implement the below case but Java is importing this import org.w3c.dom.Node (document object model) so got stuck.
Insertion Cases
Insert into Empty Array
If value to be inserted less than everything, insert in the beginning.
If value to be inserted greater than everything, insert in the last.
Could be in between if value less than/greater than certain values in LL.
import java.util.*;
public class MainLinkedList {
public static void main(String[] args) {
LinkedList<Integer> llist = new LinkedList<Integer>();
llist.add(10);
llist.add(30);
llist.add(50);
llist.add(60);
llist.add(90);
llist.add(1000);
System.out.println("Old LinkedList " + llist);
//WHat if you want to insert 70 in a sorted LinkedList
LinkedList<Integer> newllist = insertSortedLL(llist, 70);
System.out.println("New LinkedList " + newllist);
}
public static LinkedList<Integer> insertSortedLL(LinkedList<Integer> llist, int value){
llist.add(value);
Collections.sort(llist);
return llist;
}
}
If we use listIterator the complexity for doing get will be O(1).
public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {
private static final long serialVersionUID = 1L;
public boolean orderedAdd(T element) {
ListIterator<T> itr = listIterator();
while(true) {
if (itr.hasNext() == false) {
itr.add(element);
return(true);
}
T elementInList = itr.next();
if (elementInList.compareTo(element) > 0) {
itr.previous();
itr.add(element);
System.out.println("Adding");
return(true);
}
}
}
}
This might serve your purpose perfectly:
Use this code:
import java.util.*;
public class MainLinkedList {
private static LinkedList<Integer> llist;
public static void main(String[] args) {
llist = new LinkedList<Integer>();
addValue(60);
addValue(30);
addValue(10);
addValue(-5);
addValue(1000);
addValue(50);
addValue(60);
addValue(90);
addValue(1000);
addValue(0);
addValue(100);
addValue(-1000);
System.out.println("Linked List is: " + llist);
}
private static void addValue(int val) {
if (llist.size() == 0) {
llist.add(val);
} else if (llist.get(0) > val) {
llist.add(0, val);
} else if (llist.get(llist.size() - 1) < val) {
llist.add(llist.size(), val);
} else {
int i = 0;
while (llist.get(i) < val) {
i++;
}
llist.add(i, val);
}
}
}
This one method will manage insertion in the List in sorted manner without using Collections.sort(list)
You can do it in log (N) time Complexity simply. No need to iterate through all the values. you can use binary search to add value to sorted linked list.just add the value at the position of upper bound of that function.
Check code... you may understand better.
public static int ubound(LinkedList<Integer> ln, int x) {
int l = 0;
int h = ln.size();
while (l < h) {
int mid = (l + h) / 2;
if (ln.get(mid) <= x) l = mid + 1;
else h = mid;
}
return l;
}
public void solve()
{
LinkedList<Integer> ln = new LinkedList<>();
ln.add(4);
ln.add(6);
ln.add(ubound(ln, 5), 5);
out.println(ln);
}
Output : [4, 5, 6]
you can learn about binary search more at : https://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/
#Atrakeur
"sorting all the list each time you add a new element isn't efficient"
That's true, but if you need the list to always be in a sorted state, it is really the only option.
"The best way is to insert the element directly where it has to be (at his correct position). For this, you can loop all the positions to find where this number belong to"
This is exactly what the example code does.
"or use Collections.binarySearch to let this highly optimised search algorithm do this job for you"
Binary search is efficient, but only for random-access lists. So you could use an array list instead of a linked list, but then you have to deal with memory copies as the list grows. You're also going to consume more memory than you need if the capacity of the list is higher than the actual number of elements (which is pretty common).
So which data structure/approach to take is going to depend a lot on your storage and access requirements.
[edit]
Actually, there is one problem with the sample code: it results in multiple scans of the list when looping.
int i = 0;
while (llist.get(i) < val) {
i++;
}
llist.add(i, val);
The call to get(i) is going to traverse the list once to get to the ith position. Then the call to add(i, val) traverses it again. So this will be very slow.
A better approach would be to use a ListIterator to traverse the list and perform insertion. This interface defines an add() method that can be used to insert the element at the current position.
Have a look at com.google.common.collect.TreeMultiset.
This is effectively a sorted set that allows multiple instances of the same value.
It is a nice compromise for what you are trying to do. Insertion is cheaper than ArrayList, but you still get search benefits of binary/tree searches.
Linked list isn't the better implementation for a SortedList
Also, sorting all the list each time you add a new element isn't efficient.
The best way is to insert the element directly where it has to be (at his correct position).
For this, you can loop all the positions to find where this number belong to, then insert it, or use Collections.binarySearch to let this highly optimised search algorithm do this job for you.
BinarySearch return the index of the object if the object is found in the list (you can check for duplicates here if needed) or (-(insertion point) - 1) if the object isn't allready in the list (and insertion point is the index where the object need to be placed to maintains order)
You have to find where to insert the data by knowing the order criteria.
The simple method is to brute force search the insert position (go through the list, binary search...).
Another method, if you know the nature of your data, is to estimate an insertion position to cut down the number of checks. For example if you insert 'Zorro' and the list is alphabetically ordered you should start from the back of the list... or estimate where your letter may be (probably towards the end).
This can also work for numbers if you know where they come from and how they are distributed.
This is called interpolation search: http://en.wikipedia.org/wiki/Interpolation_search
Also think about batch insert:
If you insert a lot of data quickly you may consider doing many insertions in one go and only sort once afterwards.
Solution of Amruth, simplified:
public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {
private static final long serialVersionUID = 1L;
public boolean orderedAdd(T element) {
ListIterator<T> itr = listIterator();
while(itr.hasNext()) {
if (itr.next().compareTo(element) > 0) {
itr.previous();
break;
}
}
itr.add(element);
}
}
Obviously it's O(n)

Categories

Resources