【问题标题】:Java collection supporting: duplicate values, fast add, fast remove, fast min value?Java 集合支持:重复值、快速添加、快速删除、快速最小值?
【发布时间】:2014-09-24 11:57:57
【问题描述】:

问题:是否有人知道具有以下特征的集合的 Java 实现(我现在没有时间/知识来开发自己的)?

  • 快速添加
  • 快速随机访问删除
  • 快速最小值
  • 重复

用例的浓缩(过度简化)版本是:

  • 我有一个跟踪“时间”的课程,称之为TimeClass
  • 事件以单调递增的时间开始(时间不是唯一的),但可以按任意顺序结束
  • 当活动开始时,他们会将开始时间报告给TimeClass
  • 活动结束后,他们再次向TimeClass 报告开始时间
  • TimeClass 在事件开始时将事件的开始时间添加到集合*快速添加
  • TimeClass 在事件结束时从该集合*中删除事件的开始时间(快速随机访问删除
  • TimeClass 能够报告尚未完成的最低开始时间(快速最小值

*collection 视为:Collection<Time> implements Comparable<Time>

因为我不确定我的系统(TimeClass 所在的系统)的运行时行为是什么,所以我使用这些集合快速对以下场景进行了基准测试:TreeMultiSet (Guava)、@987654331 @(番石榴),ArrayList

注意,根据使用的集合,最小值以不同的方式实现(记住元素是按递增顺序添加的):TreeMultiSet.firstEntry().getElement()MinMaxPriorityQueue.peekFirst()ArrayList.get(0)

加 1,000,000:

  • TreeMultiSet: 00:00.897 (m:s.ms)
  • List: 00:00.068 (m:s.ms)
  • MinMaxPriorityQueue: 00:00.658 (m:s.ms)

添加 1,删除 1,重复 1,000,000 次:

  • TreeMultiSet: 00:00.673 (m:s.ms)
  • List: 00:00.416 (m:s.ms)
  • MinMaxPriorityQueue: 00:00.469 (m:s.ms)

按顺序添加 10,000,按顺序删除所有:

  • TreeMultiSet: 00:00.068 (m:s.ms)
  • List: 00:00.031 (m:s.ms)
  • MinMaxPriorityQueue: 00:00.048 (m:s.ms)

按顺序添加 10,000 个,按随机顺序删除所有:

  • TreeMultiSet: 00:00.046 (m:s.ms)
  • List: 00:00.352 (m:s.ms)
  • MinMaxPriorityQueue: 00:00.888 (m:s.ms)

目前的想法:

我倾向于使用TreeMultiSet,因为它具有最稳定的性能并且似乎降级最优雅。 我希望得到更多建议

谢谢

--编辑--

示例伪代码按顺序添加,按随机顺序删除所有

benchmark(){
    int benchmarkSize = 1000000;
    int benchmarkRepetitions = 100;
    Duration totalDuration = Duration.fromMilli(0);
    TimeClass timeClass = new TimeClassImplementation();
    for (int i = 0; i < benchmarkRepetitions; i++)
        totalDuration += benchmarkRun(timeClass,benchmarkSize);
    System.out.println(totalDuration);
}

Duration benchmarkRun(TimeClass timeClass, int count){
    List<Time> times = createMonotonicallyIncreasingTimes(count)

    // monotonically increasing times to add from
    List<Time> timesToAddFrom = copy(times)

    // random times to remove from
    List<Time> timesToRemoveFrom = shuffleUniformly(copy(times))

    Time startTime = now()

    // add all times
    for(Time time: timesToAddFrom) {
        Time min = timeClass.addTimeAndGetMinimumValue(time);
        // don't use min value
    }

    // remove all times
    for(Time time: timesToRemoveFrom) {
        Time min = timeClass.removeTimeAndGetMinimumValue(time);
        // don't use min value
    }

    Time finishTime = now()

    return finishTime - startTime;
}

【问题讨论】:

  • “我已经快速对以下场景进行了基准测试”。你是怎么做到的?向我们展示您的基准代码。
  • 最小值取决于值本身还是添加顺序?
  • @Tichodroma,两点:(1)我现在添加了一些伪代码(假设传入的 timeClass 实例具有不同的底层实现,使用不同的集合)(2)有一个错误我运行 LinkedList 两次而从未运行 MinMaxPriorityQueue 的代码,我现在重新运行以获取 MinMaxPriorityQueue 编号
  • @udalmik 值本身 Time 实现 Comparable
  • 坏消息是,Java 中的基准测试比预期的要困难得多。任何花费几分之一秒的测量结果本质上只是(低质量)随机数,无法用于任何事情,仅与实际使用性能略有相关(在代码预热后等)。见this question

标签: java data-structures collections guava


【解决方案1】:

最好的选择是树状图:

http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html

O(log n) 几乎适用于所有操作。您可以将密钥重新排序。

还有一个来自 Google (guava) 的 MinMaxPriorityQueue

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/MinMaxPriorityQueue.html

虽然删除是 O(n),但所有其他操作都是 O(log n)

【讨论】:

  • 正如我的问题中所解释的,我已经尝试过 MinMaxPriorityQueue。此外,如果没有包装器,TreeMap 将如何满足我的需求?我没有键,因为 Times 可以有重复的值。我可以在值中保留一个计数器(例如 Map
  • 当然,我很欣赏您的意见,但是使键唯一会改变问题
  • @user1500191:你所说的完全离题。数据结构可以在不牺牲性能的情况下具有非唯一条目。对于 Multiset 之类的情况,只需在内部存储唯一元素以及每个元素的 count,同时通过 API 将其呈现为同一元素的多个副本,这非常简单。
猜你喜欢
  • 1970-01-01
  • 2020-05-10
  • 1970-01-01
  • 1970-01-01
  • 2022-11-18
  • 1970-01-01
  • 2015-12-29
  • 1970-01-01
  • 2012-10-02
相关资源
最近更新 更多