【问题标题】:a collection data structure to keep items sorted用于保持项目排序的集合数据结构
【发布时间】:2015-07-01 14:15:24
【问题描述】:

我有一个使用ArrayList<T> 的程序,并且该类型T 也实现了Comparable<T>。我需要保持该列表排序。

现在,当我插入一个新项目时,我将它添加到ArrayList,然后调用Collections.sort(myArrayList)。

每次插入新项目时使用Collections.sort 进行排序是否会严重损害运行时复杂性?

是否有更合适的数据结构可以用来始终保持列表排序?我知道一个名为 PriorityQueue 的结构,但我还需要能够按索引获取列表的元素。

编辑: 在我的具体情况下,插入一个新项目比获取一个已经存在的项目要少得多,所以最终一个好的建议也可能是继续使用ArrayList,因为它获取一个项目的时间复杂度是恒定的。但是,如果您知道其他任何事情...

【问题讨论】:

  • TreeSet 是你的朋友。
  • 您不能/不允许将任何新元素插入其排序位置的任何特殊原因?
  • @kocko TreeSet 也不提供随机访问。
  • 代替 Collections.sort,您可以使用二进制搜索来查找插入点 - 这样会更有效。

标签: java data-structures


【解决方案1】:

看起来Collection.Sort 实际上是这里的方式,因为当集合已经几乎排序时,在最坏的情况下排序不会超过 O(n)。

【讨论】:

    【解决方案2】:

    除了在每次插入后使用Collections.sort(myArrayList),您可能想做一些更聪明的事情,因为您知道每次插入元素时,您的集合都已经排序。

    Collections.sort(myArrayList) 需要 0(nlogn) 时间,您可以使用 Collections.binarySearch 在 O(n) 时间内在有序集合中执行有序插入。如果集合按升序排列Collections.binarySearch,则返回您要查找的元素的索引(如果存在)或(-(insertion point) - 1)。在插入元素之前,您可以使用Collections.binarySearch(O(logn)时间)查找它。完成后,您可以导出插入新元素的索引。然后,您可以在 O(n) 时间内添加带有 addAt 的元素。整个插入复杂度以addAt 为界,因此您可以在 O(n) 时间内在 ArrayList 中进行有序插入。

    【讨论】:

    • 来自Collections.sort(List<T>) 的文档:“此实现是一种稳定的、自适应的、迭代的合并排序,当输入数组部分排序时,它需要的比较次数远少于 n 次 lg(n)。”
    • "远小于 n lg(n)" 并不一定意味着最坏情况下的 O(n)。此外,据我所知,合并排序还需要一个临时的集合副本,而 binarySearch 则不需要(我可能错了)。
    • 正如您自己指出的那样,列表已经排序,但只有一个元素。 Collections.sort() 的最坏情况行为不适用。 “如果输入数组接近排序,则实现需要大约 n 次比较。临时存储要求与接近排序的输入数组的一个小常数不同......”
    • 所以从安迪的评论中,我了解到 Collections.sort() (你如何像在答案或问题中那样将代码标记为灰色? ctrl+k 在这里不起作用)是实际上并没有那么糟糕,因为当它几乎排序时,在最坏的情况下它会是 O(n)?如果我只是遍历列表并查找索引,这是类似的。
    • 从 Java 7 开始,Collections.sort 实现了 Python 的 TimSort 的修改版本,对于部分有序的集合,它需要的比较次数少于 lg(N!),只需 N-1。由于您的数组始终是排序的,但只有一个元素,我们可以合理地假设 Collections.sort 的最坏情况是 O(n)。
    【解决方案3】:

    List 是一个有序集合,这意味着你需要具备使用索引访问的能力。如果集合在内部对元素进行混洗或排序,则插入顺序将与内部数据结构中元素的顺序不同。所以你不能再依赖基于索引的访问了。因此 Sun 没有提供 SortedList 或 TreeList 类。这就是你使用 Collections.sort(..)

    的原因

    Apache commons-collections 确实提供了一个 TreeList 类,但它不是一个排序列表,之所以这样调用是因为它使用树数据结构在内部存储元素。在此处查看其文档 - http://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/list/TreeList.html

    【讨论】:

      【解决方案4】:

      单个数据结构不能同时提供排序和基于索引的检索。如果输入集限制在几百或几千个,您可以保持两个数据结构并行。

      例如,ArrayList 用于基于索引的检索,TreeMap(或优先级队列)用于排序。

      【讨论】:

      • -1 一个简单的二叉树可以通过跟踪每个子树中有多少孩子来轻松支持基于 O(log n) 索引的检索。或具有 O(1) 检索但 O(n) 插入的排序数组列表。
      • @BlueRaja-DannyPflughoeft 请详细说明树中基于索引的检索。
      • 左子树有 20 项,右子树有 30 项,用户想要索引 25。由于树是有序的,所以 1-20 项在左子树中,21-50在右边。所以递归到右子树,寻找索引 5。我对我的weighted item randomizer(特别是here)使用了这个方法
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-20
      • 2015-10-23
      • 1970-01-01
      • 2012-05-03
      • 2016-01-02
      相关资源
      最近更新 更多