为什么Java中没有SortedList?

2022-08-31 04:13:55

在Java中,有SortedSetSortedMap接口。两者都属于Java集合框架,并提供一种访问元素的排序方式。

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

任何想法为什么它设计成这样?


答案 1

列表迭代器首先保证您按照列表的内部顺序(又名.插入顺序)。更具体地说,它是按照您插入元素的顺序或您操作列表的方式进行的。排序可以看作是对数据结构的操纵,有几种方法可以对列表进行排序。

我将按照我个人认为的有用性顺序对方式进行排序:

1. 考虑改用或收集SetBag

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

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

此外,如果您确定不需要担心(或拥有)重复的元素,则可以改用TreeSet<T>。它实现和接口,并按照您可能从列表中期望的那样工作:SortedSetNavigableSet

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"

如果您不想要自然排序,则可以使用采用比较器<T>构造函数参数。

或者,您可以使用多集(也称为Bags),这是一个允许重复元素的,而是有它们的第三方实现。最值得注意的是,从番石榴图书馆有一个树多,它的工作原理很像.SetTreeSet

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

如上所述,s 的排序是对数据结构的操作。因此,对于您需要以各种方式进行排序的“一个事实来源”的情况,那么手动排序就是要走的路。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"

使用比较器

一个明显的好处是,您可以在该方法中使用比较器。Java还为提供了一些实现,例如排序规则器,这对于区分语言环境的排序字符串很有用。下面是一个示例:sortComparator

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

Collections.sort(strings, usCollator);

并发环境中的排序

但请注意,在并发环境中使用该方法并不友好,因为集合实例将作,您应该考虑改用不可变集合。这是 Guava 在 Ordering 类中提供的内容,是一个简单的单行代码:sort

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

3. 用java.util.PriorityQueue

虽然Java中没有排序列表,但是有一个排序队列,它可能也适用于您。它是java.util.PriorityQueue类。

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

在排序的集合中,您很可能不想操作内部数据结构,这就是为什么PriorityQueue不实现List接口的原因(因为这将使您可以直接访问其元素)。

迭代器注意事项PriorityQueue

该类实现 和 接口,以便可以像往常一样对其进行迭代。但是,不保证迭代器按排序顺序返回元素。相反(正如Alderath在评论中指出的那样),您需要排队直到空。PriorityQueueIterable<E>Collection<E>poll()

请注意,您可以通过采用任何集合的构造函数将列表转换为优先级队列:

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 类,该类在每次添加新元素时进行排序。根据您的实现,这可能会变得相当繁重的计算量,并且毫无意义,除非您想将其作为练习,因为有两个主要原因:

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

但是,如果您想将其作为练习,这里有一个代码示例来帮助您入门,它使用抽象类: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();
    }

}

请注意,如果您尚未重写所需的方法,则 来自 的默认实现将引发 s。AbstractListUnsupportedOperationException


答案 2

因为 List 的概念与自动排序集合的概念不兼容。List 的要点是,在调用 list.add(7, elem) 之后,对 list.get(7) 的调用将返回 。使用自动排序的列表,元素可能最终位于任意位置。elem


推荐