简体   繁体   English

如何在不使用Collections.sort()的情况下获得Java中的排序列表行为?

[英]How can I get Sorted List behavior in Java without using Collections.sort()?

I understand that Java does not possess a Sorted List for various conceptual reasons, but consider the case I need to have a collection which is kind of like a Priority Queue but also allows me random access (indexable), in other words, I need a List that follows a particular ordering. 我了解Java出于各种概念上的原因不具备排序列表,但是考虑到我需要拥有一个类似于Priority Queue但还允许我进行随机访问(可索引)的集合的情况,换句话说,我需要一个遵循特定顺序的列表。 I would prefer not to use Collections.sort() 我宁愿使用Collections.sort()

Preferable operation constraints: 首选操作约束:

retrieve - O(1) (index-based random access) 检索-O(1)(基于索引的随机访问)
search - O(log n) 搜索-O(log n)
insert - O(log n) 插入-O(log n)
delete - O(log n) 删除-O(log n)

An iterator over the collection should give me all elements in Sorted Order (based on predefined Comparator supplied during instantiation of the data-structure) 集合上的迭代器应按排序顺序为我提供所有元素(基于在数据结构实例化时提供的预定义Comparator

I would prefer to use Java's inbuilt library to accomplish this, but feel free to suggest external libraries as well. 我宁愿使用Java的内置库来完成此操作,但也可以建议外部库。

EDIT: TreeSet won't do as index based access is difficult, using wrapper collections is also not my best choice as removal would imply I need to remove from both collections. 编辑:TreeSet不会做,因为基于索引的访问很困难,使用包装器集合也不是我的最佳选择,因为删除意味着我需要从两个集合中删除。

EDIT2: I was unable to find an implementation and/or documentation for an indexable skip list this seems a bit relevant, can anyone help me find it ? EDIT2:我无法找到indexable skip list的实现和/或文档,这似乎有些相关,有人可以帮助我找到它吗? Any comments for or against the data structure proposed is also welcome. 也欢迎对提议的数据结构提出或反对的任何评论。

EDIT3: Though this may not be the most perfect answer, I want to add this piece of code that I wrote so that anyone who has similar problems for the need of a sorted list can use this if they find it useful. EDIT3:虽然这可能不是最完美的答案,但是我想添加这段代码,以便任何有类似问题但需要排序列表的人都可以使用它,如果他们觉得有用的话。

Do check for errors (if any), and suggest improvements (especially to the sortedSubList method) 请检查是否有错误(如有),并提出改进建议(尤其是对sortedSubList方法)

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;

public class SortedList<E> extends ArrayList<E> {
    private final Comparator<? super E> comparator;

    public SortedList(Comparator<? super E> comparator) {
        this.comparator = comparator;
    }

    public SortedList(int initialCapacity, Comparator<? super E> comparator) {
        super(initialCapacity);
        this.comparator = comparator;
    }

    @Override
    public boolean add(E e) {
        if (comparator == null)
            return super.add(e);
        if (e == null)
            throw new NullPointerException();
        int start = 0;
        int end = size() - 1;
        while (start <= end) {
            int mid = (start + end) / 2;
            if (comparator.compare(get(mid), e) == 0) {
                super.add(mid, e);
                return true;
            }
            if (comparator.compare(get(mid), e) < 0) {
                end = mid - 1;
            }
            else {
                start = mid + 1;
            }
        }
        super.add(start, e);
        return true;
    }

    @Override
    public boolean contains(Object o) {
        if (comparator == null)
            return super.contains(o);
        if (o == null)
            return false;
        E other = (E) o;
        int start = 0;
        int end = size() - 1;
        while (start <= end) {
            int mid = (start + end) / 2;
            if (comparator.compare(get(mid), other) == 0) {
                return true;
            }
            if (comparator.compare(get(mid), other) < 0) {
                end = mid - 1;
            }
            else {
                start = mid + 1;
            }
        }
        return false;
    }

    @Override
    public int indexOf(Object o) {
        if (comparator == null)
            return super.indexOf(o);
        if (o == null)
            throw new NullPointerException();
        E other = (E) o;
        int start = 0;
        int end = size() - 1;
        while (start <= end) {
            int mid = (start + end) / 2;
            if (comparator.compare(get(mid), other) == 0) {
                return mid;
            }
            if (comparator.compare(get(mid), other) < 0) {
                end = mid - 1;
            }
            else {
                start = mid + 1;
            }
        }
        return -(start+1);
    }

    @Override
    public void add(int index, E e) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean addAll(int index, Collection<? extends E> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public E set(int index, E e) {
        throw new UnsupportedOperationException();
    }

    public SortedList<E> sortedSubList(int fromIndex, int toIndex) {
        SortedList<E> sl = new SortedList<>(comparator);
        for (int i = fromIndex; i < toIndex; i++)
            sl.add(get(i));
        return sl;
    }
}

It's hard to get O(1) indexing and O(log n) insertion/deletion in the same data structure. 在同一数据结构中很难获得O(1)索引和O(log n)插入/删除。 O(1) indexing means we can't afford the link-following involved in indexing a tree, list, skip list, or other link-based data structure, while O(log n) modification means we can't afford to shift half the elements of an array on every insertion. O(1)索引意味着我们无法负担对树,列表,跳过列表或其他基于链接的数据结构建立索引所涉及的链接跟踪,而O(log n)修改意味着我们无法负担一半的移位每次插入时数组的元素。 I don't know if it's possible to fulfill these requirements simultaneously. 我不知道是否有可能同时满足这些要求。

If we relax one of these requirements, things become much easier. 如果我们放宽这些要求之一,事情就会变得容易得多。 For example, O(log n) for all operations can be achieved by an indexable skip list or a self-balancing BST with nodes that keep track of the size of the subtree rooted at the node. 例如,所有操作的O(log n)都可以通过可索引的跳过列表或具有节点的自平衡BST来实现,该节点跟踪以该节点为根的子树的大小。 Neither of these can be built on top of the skip list or BST in Java's standard library, though, so you'd probably need to install another library or write your own data structure. 但是,这些都不能建立在Java标准库的跳过列表或BST之上,因此您可能需要安装另一个库或编写自己的数据结构。

O(1) indexing, O(log n) search, and O(n) insert and delete can be done by keeping a sorted ArrayList and using Collections.binarySearch to search for elements or insert/delete positions. 可以通过保留排序的ArrayList并使用Collections.binarySearch搜索元素或插入/删除位置来完成O(1)索引编制,O(log n)搜索以及O(n)插入和删除操作。 You never need to call Collections.sort , but you still need to call the ArrayList's O(n) insert and delete methods. 您不需要调用Collections.sort ,但仍然需要调用ArrayList的O(n)插入和删除方法。 This is probably the easiest option to build on top of Java's built-in tools. 这可能是在Java内置工具之上构建的最简单的选择。 Note that with recent Java versions, Collections.sort is an adaptive mergesort that would take O(n) time to sort an array where only the last element is out of sorted order, so you could probably get away with relying on Collections.sort . 请注意,在最新的Java版本中, Collections.sort是一种自适应mergesort,将花费O(n)时间对仅最后一个元素不按排序顺序排列的数组进行排序,因此您可以摆脱依赖Collections.sort However, that's an implementation detail that alternative Java implementations don't have to follow. 但是,这是实现细节,其他Java实现不必遵循。

If your primary goal is O(1) for indexed lookup ( get() ), then you can implement your own class implementing List , backed by an array, using Arrays.binarySearch() . 如果您的主要目标是索引查找( get() )的O(1),则可以使用Arrays.binarySearch()实现自己的类,该类实现List ,并由数组支持。

retrieve: get(int)         - O(1)     - array index
search:   contains(Object) - O(log n) - binarySearch
          indexOf(Object)  - O(log n) - binarySearch
insert:   add(E)           - O(n)     - binarySearch + array shift
delete:   remove(int)      - O(n)     - array shift
          remove(Object)   - O(n)     - binarySearch + array shift

The add(E) method is violating the List definition (append), but is consistent with the Collection definition. add(E)方法违反了List定义(追加),但与Collection定义一致。

The following methods should throw UnsupportedOperationException : 以下方法应引发UnsupportedOperationException

add(int index, E element)
addAll(int index, Collection<? extends E> c)
set(int index, E element)

If duplicate values are not allowed, which could be a logical restriction, consider also implementing NavigableSet , which is a SortedSet . 如果不允许重复值(这可能是一个逻辑限制),请考虑同时实现NavigableSet ,它是SortedSet

Build a custom collection that is backed by an ArrayList and a TreeSet. 构建由ArrayList和TreeSet支持的自定义集合。 Delegate the random access to the ArrayList and the search to the TreeSet. 委派对ArrayList的随机访问和对TreeSet的搜索。 Of course this means that every write operation will be very expensive, as it will have to sort the ArrayList every time. 当然,这意味着每次写操作都将非常昂贵,因为每次都必须对ArrayList进行排序。 But the reads should be very efficient. 但是读取应该非常有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java的Collections.sort如何覆盖要排序的List - How does Java's Collections.sort overwrite the List to be sorted 如何不使用诸如Collections.sort之类的排序方法就基于姓氏对LinkedList进行排序 - How can I sort a LinkedList based on the last names without using an sort methods such as Collections.sort 如何使用具有 2 个参数的 Collections.sort 方法以升序对 Java 中的给定列表进行排序? - How can I use the Collections.sort method with 2 parameters in order to sort in ascending order a given list in Java? 如何使用Collections.sort()使我的数组按字母顺序排序? -Java - How can I make my Arrays sort Alphebetically using Collections.sort()? -Java 如何取消Collections.sort() - How can I cancel Collections.sort() Collections.Sort()的行为; - Behavior of Collections.Sort(); 不知道如何在不使用Collections.sort的情况下将数组列表从最小到最大排序 - Don't know how to sort an array list from least to greatest without using Collections.sort 排序列表<list<integer> > 使用 java Collections.sort() </list<integer> - sorting a List<List<Integer>> using java Collections.sort() 如何不使用collections.sort()按字母顺序对数组列表排序 - How to sort an arraylist alphabetically without using collections.sort(); Java Collections.sort 用于通配符列表(List<!--?--> ) - Java Collections.sort for wildcard list (List<?>)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM