samedi 5 avril 2014

Collections - y a-t-il une méthode concat rapide pour une liste chaînée en Java ? -Débordement de pile


How can I concat two linked lists in O(1) with Java via jdk1.6, google or apache commons collection or whatever? E.g. in the jdk there is only the addAll method which is O(n).


Another feature I miss is to concat two lists where each of them could be in inverse order. To illustrate this assume two lists a->b->c and e->f->g could merged into



  1. a->b->c->e->f->g

  2. a->b->c->g->f->e

  3. c->b->a->e->f->g

  4. c->b->a->g->f->e


Do you know of such a list implemenation or do I have to implement my own linked list? It would be also helpful to know how to tweak existing solutions (e.g. the jdk LinkedList has a lot of private methods only). These features seems to me very obvious, hopefully I am not missing something stupid.


As MicSim pointed out the question Merge two lists in constant time in Java is related but not a real duplicate! Now the questions are:



  1. is it possible with other collection libs?

  2. how to concat the inverse?




If you are willing to settle for Iterable result, you can use google-collections Iterables.concat and Iterables.reverse


http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Iterables.html


public static <T> Iterable<T> concat(Iterable<? extends T> a,
Iterable<? extends T> b)

public static <T> Iterable<T> concat(Iterable<? extends T> a,
Iterable<? extends T> b,
Iterable<? extends T> c)

public static <T> Iterable<T> concat(Iterable<? extends T> a,
Iterable<? extends T> b,
Iterable<? extends T> c,
Iterable<? extends T> d)

public static <T> Iterable<T> concat(Iterable<? extends T>... inputs)

public static <T> Iterable<T> concat(Iterable<? extends Iterable<? extends T>> inputs)



The only solution I see at the moment is to implement List, make a constructor like:


public EnhancedList (List l1, List l2)

and override all methods. In such solution it's actually not important whether you want to concat LinkedLists or any other lists.




I'd think this wouldn't be too difficult to write with any kind of base list construct since insertion in the middle or the end of a list in a Linked list is O(1).




Adapting the LinkedList to get O(1) concat in the jdk will work if:



  1. the method entry() and the variables header and size and the inner class Entry would be protected

  2. addAll would detect LinkedList and then doing sth. like:

    JdkLinkedList secondList = (JdkLinkedList) secondColl;
    int numNew = secondList.size();
    if (numNew == 0) return false;
    modCount++;
    Entry<E> successor = (index == size ? header : entry(index));
    Entry<E> predecessor = successor.previous;
    // TODO LATER if reverse


    // connect the last element of this list with the first element of the second list
    // linked list is implemented as a 'cycle' => header.next == first element of second list
    Entry<E> first = secondList.header.next;
    predecessor.next = first;
    first.previous = predecessor;


    // append the last element of the second list with the rest of this list
    Entry<E> last = secondList.header;
    successor.previous = last;
    last.next = successor;




For the concat I would suggest you do the following:



  • Make sure all of your parameters/variables are declared as List<...> not LinkedList<...>

  • Change the new LinkedList<...>(); to new ArrayList<...>();

  • profile the application

  • Change the new ArrayList<...> to new LinkedList<...>();

  • profile the application


Depending on your usage ArrayList can be significantly faster than LinkedList. Also looking at the profile data you can see how much of a performance hit you have by using addAll - if it isn't that large don't bother "fixing" it.


For some things your experiences with other languages will not hold true. You may find that addAll meets your requirements in Java.


If you were to write your own concatable list make sure it conforms to the List interface then change your code and re-profile it and make sure it is faster. If it isn't then throw it away and stick with the standard List types.




FastList from javolution is not an out-of-the-box solution but with the tail() and head() quite close to my favourite.


I think trove is the solution, although no convenient method exist for invert or addAll in O(1).




It's a little late but for others who are searching for the same kind of problem you can use:


ImmutableList.<String> builder().addAll(firstList).addAll(secondList).build()


How can I concat two linked lists in O(1) with Java via jdk1.6, google or apache commons collection or whatever? E.g. in the jdk there is only the addAll method which is O(n).


Another feature I miss is to concat two lists where each of them could be in inverse order. To illustrate this assume two lists a->b->c and e->f->g could merged into



  1. a->b->c->e->f->g

  2. a->b->c->g->f->e

  3. c->b->a->e->f->g

  4. c->b->a->g->f->e


Do you know of such a list implemenation or do I have to implement my own linked list? It would be also helpful to know how to tweak existing solutions (e.g. the jdk LinkedList has a lot of private methods only). These features seems to me very obvious, hopefully I am not missing something stupid.


As MicSim pointed out the question Merge two lists in constant time in Java is related but not a real duplicate! Now the questions are:



  1. is it possible with other collection libs?

  2. how to concat the inverse?



If you are willing to settle for Iterable result, you can use google-collections Iterables.concat and Iterables.reverse


http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Iterables.html


public static <T> Iterable<T> concat(Iterable<? extends T> a,
Iterable<? extends T> b)

public static <T> Iterable<T> concat(Iterable<? extends T> a,
Iterable<? extends T> b,
Iterable<? extends T> c)

public static <T> Iterable<T> concat(Iterable<? extends T> a,
Iterable<? extends T> b,
Iterable<? extends T> c,
Iterable<? extends T> d)

public static <T> Iterable<T> concat(Iterable<? extends T>... inputs)

public static <T> Iterable<T> concat(Iterable<? extends Iterable<? extends T>> inputs)


The only solution I see at the moment is to implement List, make a constructor like:


public EnhancedList (List l1, List l2)

and override all methods. In such solution it's actually not important whether you want to concat LinkedLists or any other lists.



I'd think this wouldn't be too difficult to write with any kind of base list construct since insertion in the middle or the end of a list in a Linked list is O(1).



Adapting the LinkedList to get O(1) concat in the jdk will work if:



  1. the method entry() and the variables header and size and the inner class Entry would be protected

  2. addAll would detect LinkedList and then doing sth. like:

    JdkLinkedList secondList = (JdkLinkedList) secondColl;
    int numNew = secondList.size();
    if (numNew == 0) return false;
    modCount++;
    Entry<E> successor = (index == size ? header : entry(index));
    Entry<E> predecessor = successor.previous;
    // TODO LATER if reverse


    // connect the last element of this list with the first element of the second list
    // linked list is implemented as a 'cycle' => header.next == first element of second list
    Entry<E> first = secondList.header.next;
    predecessor.next = first;
    first.previous = predecessor;


    // append the last element of the second list with the rest of this list
    Entry<E> last = secondList.header;
    successor.previous = last;
    last.next = successor;



For the concat I would suggest you do the following:



  • Make sure all of your parameters/variables are declared as List<...> not LinkedList<...>

  • Change the new LinkedList<...>(); to new ArrayList<...>();

  • profile the application

  • Change the new ArrayList<...> to new LinkedList<...>();

  • profile the application


Depending on your usage ArrayList can be significantly faster than LinkedList. Also looking at the profile data you can see how much of a performance hit you have by using addAll - if it isn't that large don't bother "fixing" it.


For some things your experiences with other languages will not hold true. You may find that addAll meets your requirements in Java.


If you were to write your own concatable list make sure it conforms to the List interface then change your code and re-profile it and make sure it is faster. If it isn't then throw it away and stick with the standard List types.



FastList from javolution is not an out-of-the-box solution but with the tail() and head() quite close to my favourite.


I think trove is the solution, although no convenient method exist for invert or addAll in O(1).



It's a little late but for others who are searching for the same kind of problem you can use:


ImmutableList.<String> builder().addAll(firstList).addAll(secondList).build()

0 commentaires:

Enregistrer un commentaire