A good Sorted List for Java

后端 未结 10 1690
离开以前
离开以前 2020-11-30 02:29

I\'m looking for a good sorted list for java. Googling around give me some hints about using TreeSet/TreeMap. But these components is lack of one thing: random access to an

相关标签:
10条回答
  • 2020-11-30 02:59

    Generally you can't have constant time look up and log time deletions/insertions, but if you're happy with log time look ups then you can use a SortedList.

    Not sure if you'll trust my coding but I recently wrote a SortedList implementation in Java, which you can download from http://www.scottlogic.co.uk/2010/12/sorted_lists_in_java/. This implementation allows you to look up the i-th element of the list in log time.

    0 讨论(0)
  • 2020-11-30 03:07

    Phuong:

    Sorting 40,000 random numbers:

    0.022 seconds

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Random;
    
    
    public class test
    {
        public static void main(String[] args)
        {
            List<Integer> nums = new ArrayList<Integer>();
            Random rand = new Random();
            for( int i = 0; i < 40000; i++ )
            {
                nums.add( rand.nextInt(Integer.MAX_VALUE) );
            }
    
            long start = System.nanoTime();
            Collections.sort(nums);
            long end = System.nanoTime();
    
            System.out.println((end-start)/1e9);
        }
    }   
    

    Since you rarely need sorting, as per your problem statement, this is probably more efficient than it needs to be.

    0 讨论(0)
  • 2020-11-30 03:07

    To test the efficiancy of earlier awnser by Konrad Holl, I did a quick comparison with what I thought would be the slow way of doing it:

    package util.collections;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.List;
    import java.util.ListIterator;
    
    /**
     *
     * @author Earl Bosch
     * @param <E> Comparable Element
     *
     */
    public class SortedList<E extends Comparable> implements List<E> {
    
        /**
         * The list of elements
         */
        private final List<E> list = new ArrayList();
    
        public E first() {
            return list.get(0);
        }
    
        public E last() {
            return list.get(list.size() - 1);
        }
    
        public E mid() {
            return list.get(list.size() >>> 1);
        }
    
        @Override
        public void clear() {
            list.clear();
        }
    
        @Override
        public boolean add(E e) {
            list.add(e);
            Collections.sort(list);
            return true;
        }
    
        @Override
        public int size() {
            return list.size();
        }
    
        @Override
        public boolean isEmpty() {
            return list.isEmpty();
        }
    
        @Override
        public boolean contains(Object obj) {
            return list.contains((E) obj);
        }
    
        @Override
        public Iterator<E> iterator() {
            return list.iterator();
        }
    
        @Override
        public Object[] toArray() {
            return list.toArray();
        }
    
        @Override
        public <T> T[] toArray(T[] arg0) {
            return list.toArray(arg0);
        }
    
        @Override
        public boolean remove(Object obj) {
            return list.remove((E) obj);
        }
    
        @Override
        public boolean containsAll(Collection<?> c) {
            return list.containsAll(c);
        }
    
        @Override
        public boolean addAll(Collection<? extends E> c) {
    
            list.addAll(c);
            Collections.sort(list);
            return true;
        }
    
        @Override
        public boolean addAll(int index, Collection<? extends E> c) {
            throw new UnsupportedOperationException("Not supported.");
        }
    
        @Override
        public boolean removeAll(Collection<?> c) {
            return list.removeAll(c);
        }
    
        @Override
        public boolean retainAll(Collection<?> c) {
            return list.retainAll(c);
        }
    
        @Override
        public E get(int index) {
            return list.get(index);
        }
    
        @Override
        public E set(int index, E element) {
            throw new UnsupportedOperationException("Not supported.");
        }
    
        @Override
        public void add(int index, E element) {
            throw new UnsupportedOperationException("Not supported.");
        }
    
        @Override
        public E remove(int index) {
            return list.remove(index);
        }
    
        @Override
        public int indexOf(Object obj) {
            return list.indexOf((E) obj);
        }
    
        @Override
        public int lastIndexOf(Object obj) {
            return list.lastIndexOf((E) obj);
        }
    
        @Override
        public ListIterator<E> listIterator() {
            return list.listIterator();
        }
    
        @Override
        public ListIterator<E> listIterator(int index) {
            return list.listIterator(index);
        }
    
        @Override
        public List<E> subList(int fromIndex, int toIndex) {
            throw new UnsupportedOperationException("Not supported.");
        }
    
    }
    

    Turns out its about twice as fast! I think its because of SortedLinkList slow get - which make's it not a good choice for a list.

    Compared times for same random list:

    • SortedLinkList : 15731.460
    • SortedList : 6895.494
    • ca.odell.glazedlists.SortedList : 712.460
    • org.apache.commons.collections4.TreeList : 3226.546

    Seems glazedlists.SortedList is really fast...

    0 讨论(0)
  • 2020-11-30 03:07

    You need no sorted list. You need no sorting at all.

    I need to add/remove keys from the list when object is added / removed from database.

    But not immediately, the removal can wait. Use an ArrayList containing the ID's all alive objects plus at most some bounded percentage of deleted objects. Use a separate HashSet to keep track of deleted objects.

    private List<ID> mostlyAliveIds = new ArrayList<>();
    private Set<ID> deletedIds = new HashSet<>();
    

    I want to randomly select few dozens of element from the whole list.

    ID selectOne(Random random) {
        checkState(deletedIds.size() < mostlyAliveIds.size());
        while (true) {
            int index = random.nextInt(mostlyAliveIds.size());
            ID id = mostlyAliveIds.get(index);
            if (!deletedIds.contains(ID)) return ID;
        }
    }
    
    Set<ID> selectSome(Random random, int count) {
        checkArgument(deletedIds.size() <= mostlyAliveIds.size() - count);
        Set<ID> result = new HashSet<>();
        while (result.size() < count) result.add(selectOne(random));
    }
    

    For maintaining the data, do something like

    void insert(ID id) {
        if (!deletedIds.remove(id)) mostlyAliveIds.add(ID);
    } 
    
    void delete(ID id) {
        if (!deletedIds.add(id)) {
             throw new ImpossibleException("Deleting a deleted element);
        }
        if (deletedIds.size() > 0.1 * mostlyAliveIds.size()) {
            mostlyAliveIds.removeAll(deletedIds);
            deletedIds.clear();
        }
    }
    

    The only tricky part is the insert which has to check if an already deleted ID was resurrected.

    The delete ensures that no more than 10% of elements in mostlyAliveIds are deleted IDs. When this happens, they get all removed in one sweep (I didn't check the JDK sources, but I hope, they do it right) and the show goes on.

    With no more than 10% of dead IDs, the overhead of selectOne is no more than 10% on the average.

    I'm pretty sure that it's faster than any sorting as the amortized complexity is O(n).

    0 讨论(0)
提交回复
热议问题