在Java中有SortedSet和SortedMap接口。两者都属于Java Collections框架,并提供了一种访问元素的排序方式。

然而,在我的理解中,Java中没有SortedList。您可以使用java.util.Collections.sort()对列表进行排序。

知道它为什么是这样设计的吗?


因为所有列表都已经按照条目的添加顺序(FIFO顺序)“排序”了,所以可以使用java.util.Collections.sort()使用另一种顺序“使用”它们,包括元素的自然顺序。

编辑:

列表作为数据结构的基础是有趣的是插入项的顺序。

集合没有这个信息。

如果您想通过添加时间来排序,请使用List。如果您想按其他标准排序,请使用SortedSet。


列表迭代器首先保证以列表的内部顺序获取列表的元素。插入顺序)。更具体地说,它是在您插入元素的顺序或您如何操作列表。排序可以看作是对数据结构的操作,有几种方法可以对列表进行排序。

我将按照我个人认为的有用性来排序:

1. 可以考虑使用Set或Bag集合

注意:我把这个选项放在顶部,因为这是你通常想要做的。

排序集在插入时自动对集合进行排序,这意味着它在向集合中添加元素时进行排序。这也意味着您不需要手动排序。

此外,如果您确定不需要担心(或没有)重复元素,则可以使用TreeSet<T>代替。它实现了SortedSet和NavigableSet接口,并像你可能期望的那样从列表中工作:

TreeSet<String> set = new TreeSet<String>();
set.add("lol");
set.add("cat");
// automatically sorts natural order when adding

for (String s : set) {
    System.out.println(s);
}
// Prints out "cat" and "lol"

如果不想要自然排序,可以使用接受Comparator<T>的构造函数参数。

或者,您可以使用Multisets(也称为Bags),这是一个允许重复元素的集合,而不是它们的第三方实现。Guava库中最值得注意的是TreeMultiset,它的工作原理与TreeSet非常相似。

2. 使用Collections.sort()对列表进行排序

如上所述,list的排序是对数据结构的操作。因此,当你需要“一个真相来源”以各种方式排序时,手动排序是可行的。

您可以使用java.util.Collections.sort()方法对列表进行排序。下面是一个代码示例:

List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");

Collections.sort(strings);
for (String s : strings) {
    System.out.println(s);
}
// Prints out "cat" and "lol"

使用比较器

一个明显的好处是可以在sort方法中使用Comparator。Java还为Comparator提供了一些实现,例如Collator,它对于locale敏感的字符串排序非常有用。这里有一个例子:

Collator usCollator = Collator.getInstance(Locale.US);
usCollator.setStrength(Collator.PRIMARY); // ignores casing

Collections.sort(strings, usCollator);

并发环境中的排序

但是请注意,在并发环境中使用sort方法并不友好,因为集合实例将被操作,您应该考虑使用不可变的集合。这是Guava在ordered类中提供的东西,是一个简单的一行程序:

List<string> sorted = Ordering.natural().sortedCopy(strings);

3.用java.util.PriorityQueue包装列表

虽然在Java中没有排序的列表,但是有一个排序的队列,它可能同样适合你。它是java.util.PriorityQueue类。

Nico Haase在评论中链接了一个相关的问题,也回答了这个问题。

在排序集合中,您很可能不希望操作内部数据结构,这就是为什么PriorityQueue没有实现List接口(因为这会让您直接访问其元素)。

关于PriorityQueue迭代器的警告

PriorityQueue类实现了Iterable<E>和Collection<E>接口,因此它可以像往常一样迭代。但是,迭代器不能保证按排序顺序返回元素。相反(正如Alderath在评论中指出的那样),您需要轮询()队列直到空为止。

注意,你可以通过接受任何集合的构造函数将列表转换为优先级队列:

List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");

PriorityQueue<String> sortedStrings = new PriorityQueue(strings);
while(!sortedStrings.isEmpty()) {
    System.out.println(sortedStrings.poll());
}
// Prints out "cat" and "lol"

4. 编写自己的SortedList类

注意:您不必这样做。

您可以编写自己的List类,在每次添加新元素时进行排序。根据你的实现,这可能会使计算量相当大,而且毫无意义,除非你想把它作为练习,因为两个主要原因:

它打破了List<E>接口的契约,因为add方法应该确保元素驻留在用户指定的索引中。 为什么要重新发明轮子?你应该使用树集或多集,而不是在上面的第一点指出。

但是,如果你想把它作为练习,这里有一个代码示例来开始,它使用了AbstractList抽象类:

public class SortedList<E> extends AbstractList<E> {

    private ArrayList<E> internalList = new ArrayList<E>();

    // Note that add(E e) in AbstractList is calling this one
    @Override 
    public void add(int position, E e) {
        internalList.add(e);
        Collections.sort(internalList, null);
    }

    @Override
    public E get(int i) {
        return internalList.get(i);
    }

    @Override
    public int size() {
        return internalList.size();
    }

}

注意,如果您还没有覆盖所需的方法,那么AbstractList中的默认实现将抛出unsupportedoperationexception。


因为List的概念与自动排序集合的概念是不兼容的。List的意义在于调用List之后。添加(7,elem),调用list.get(7)将返回elem。在自动排序的列表中,元素可以位于任意位置。


可以这样想:List接口有add(int index, E element), set(int index, E element)这样的方法。约定是,一旦你在X位置添加了一个元素,你就会在那里找到它,除非你在它之前添加或删除元素。

如果任何列表实现都以某种顺序存储元素,而不是基于索引,那么上述列表方法就没有意义了。


另一点是插入操作的时间复杂度。 对于列表插入,期望复杂度为O(1)。 但是,排序的列表并不能保证这一点。

最重要的一点是,列表对它们的元素没有任何假设。 例如,您可以列出不实现等于或比较的东西。


List API中的第一行表示它是一个有序集合(也称为序列)。如果您对列表进行排序,则无法维护该顺序,因此Java中没有TreeList。 正如API所说,Java列表的灵感来自序列,并查看序列属性http://en.wikipedia.org/wiki/Sequence_(mathematics)

这并不意味着您不能对列表进行排序,但是Java严格遵守了他的定义,并且默认情况下不提供列表的排序版本。


https://github.com/geniot/indexed-tree-map

考虑使用索引树映射。它是一个增强的JDK的TreeSet,它提供了通过索引访问元素的功能,并且无需迭代或隐藏的底层列表来备份树,就可以找到元素的索引。该算法基于每次有变化时更新已更改节点的权重。


JavaFX 排序列表

虽然花了一些时间,但Java 8确实有一个排序的List。 http://docs.oracle.com/javase/8/javafx/api/javafx/collections/transformation/SortedList.html

正如您在javadocs中所看到的,它是JavaFX集合的一部分,旨在提供一个ObservableList上的排序视图。

更新:注意,在Java 11中,JavaFX工具包已经移到JDK之外,现在是一个独立的库。JavaFX 11可以作为可下载的SDK或从MavenCentral获得。参见https://openjfx.io


对于任何新手来说,从2015年4月开始,Android现在在支持库中有一个SortedList类,专门用于与RecyclerView一起工作。这是关于它的博客文章。


Set和Map是非线性数据结构。列表是线性数据结构。


树数据结构SortedSet和SortedMap接口使用常用的红黑树实现算法分别实现TreeSet和TreeMap。因此,它确保没有重复的项(或Map情况下的键)。

List已经维护了有序的集合和基于索引的数据结构,树不是基于索引的数据结构。 树根据定义不能包含重复项。 在List中,我们可以有副本,所以没有TreeList(即。没有SortedList)。 List按插入顺序维护元素。因此,如果我们想对列表进行排序,就必须使用java.util.Collections.sort()。它根据元素的自然顺序,将指定的列表按升序排序。


如果你正在寻找一种方法来排序元素,但也能够以一种有效的方式通过索引访问它们,你可以做以下事情:

使用随机访问列表进行存储(例如ArrayList) 确保它总是有序的

然后,要添加或删除元素,可以使用集合。binarySearch获取插入/删除索引。因为您的列表实现了随机访问,所以您可以使用确定的索引有效地修改列表。

例子:

/**
 * @deprecated
 *      Only for demonstration purposes. Implementation is incomplete and does not 
 *      handle invalid arguments.
 */
@Deprecated
public class SortingList<E extends Comparable<E>> {
    private ArrayList<E> delegate;
    
    public SortingList() {
        delegate = new ArrayList<>();
    }
    
    public void add(E e) {
        int insertionIndex = Collections.binarySearch(delegate, e);
        
        // < 0 if element is not in the list, see Collections.binarySearch
        if (insertionIndex < 0) {
            insertionIndex = -(insertionIndex + 1);
        }
        else {
            // Insertion index is index of existing element, to add new element 
            // behind it increase index
            insertionIndex++;
        }
        
        delegate.add(insertionIndex, e);
    }
    
    public void remove(E e) {
        int index = Collections.binarySearch(delegate, e);
        delegate.remove(index);
    }
    
    public E get(int index) {
        return delegate.get(index);
    }
}

(在这个答案中可以看到更完整的实现)


我认为以上都不能回答这个问题,原因如下:

Since same functionality can be achieved by using other collections such as TreeSet, Collections, PriorityQueue..etc (but this is an alternative which will also impose their constraints i.e. Set will remove duplicate elements. Simply saying even if it does not impose any constraint, it does not answer the question why SortedList was not created by java community) Since List elements do not implements compare/equals methods (This holds true for Set & Map also where in general items do not implement Comparable interface but when we need these items to be in sorted order & want to use TreeSet/TreeMap,items should implement Comparable interface) Since List uses indexing & due to sorting it won't work (This can be easily handled introducing intermediate interface/abstract class)

但没有人告诉它背后的确切原因,因为我相信这类问题最好由java社区自己来回答,因为它只有一个具体的答案,但让我尽我所能回答如下:

我们知道排序是一个昂贵的操作,列表和Set/Map之间有一个基本的区别,列表可以有重复,而Set/Map不能。 这就是我们为Set/Map提供TreeSet/TreeMap形式的默认实现的核心原因。在内部,这是一个红黑树,每个操作(插入/删除/搜索)的复杂度为O(log N),其中由于重复列表无法适合这种数据存储结构。

Now the question arises we could also choose a default sorting method for List also like MergeSort which is used by Collections.sort(list) method with the complexity of O(N log N). Community did not do this deliberately since we do have multiple choices for sorting algorithms for non distinct elements like QuickSort, ShellSort, RadixSort...etc. In future there can be more. Also sometimes same sorting algorithm performs differently depending on the data to be sorted. Therefore they wanted to keep this option open and left this on us to choose. This was not the case with Set/Map since O(log N) is the best sorting complexity.


我们有Collections.sort(arr)方法,它可以帮助对ArrayList arr进行排序。要以desc方式排序,我们可以使用集合。排序(arr Collections.reverseOrder ())