【问题标题】:Java Data StructureJava 数据结构
【发布时间】:2010-12-21 20:32:28
【问题描述】:

我正在寻找一种类似于队列的数据结构,这样我就可以拥有先进先出的行为,但理想情况下,我还可以在恒定时间内查看该队列中是否存在元素使用 HashMap,而不是使用 LinkedList 获得的线性时间。

我认为 LinkedHashMap 可能会完成这项工作,但是虽然我可以创建一个迭代器,然后取出迭代的第一个元素以生成一种 poll() 方法,但我想知道是否有更好的方法方式。

在此先感谢

【问题讨论】:

  • HashMap 没有固定的时间访问,它看起来像这样,因为内部有散列。访问时间是O(n)/bucketsize,在大多数情况下可能是1,但它仍然是O(n)/bucketsize(这是线性的)。
  • 我将其描述为 O(log(log(n)),与我观察到的非常匹配。c.f. TreeSet 是 O(log(n)),一百万个条目比 10 慢大约 5 倍。一百万个条目上的 HashSet contains() 大约比 10 慢 1.5 倍(忽略缓存行为)集合是否在缓存中会产生更大的差异。;)

标签: java data-structures


【解决方案1】:

我不知道那里是否有什么东西,但您可以轻松地创建一个由QueueHashSet 组成的复合对象。所有修改操作都需要同时在两个集合上进行,以使它们保持同步。然后您可以使用该集合进行查找,这应该非常快。

【讨论】:

    【解决方案2】:

    通常当您想要两个集合的行为时,您需要维护两个集合。一个简单的方法是拥有一个 Queue 和一个 HashSet,并在从 Queue 中删除时始终对两者执行添加并从 HashMap 中删除。

    另一种方法是使用 LinkedHashSet。这会保留添加的顺序元素,并且您可以每次删除第一个/最旧的元素。

    第三种选择是仅使用队列。虽然您可能喜欢 O(1) 查找时间,但您可能会发现只需搜索每个元素就足以满足您的要求。这可能比您预期的要快得多。即 1000 个元素应小于 10 微秒。

    编辑:我同意当您不知道长度时最好使用两个集合。

    但是,向您展示蛮力搜索也可以很快。寻找最慢的对象是不存在的对象。 (因为它必须比较每个元素)

    Queue<Point> points = new ArrayBlockingQueue<Point>(1024);
    for(int i=0;i<1000;i++)
      points.add(new Point(i,i));
    Point missing = new Point(-1, -1);
    int runs = 100 * 1000;
    long start = System.nanoTime();
    for(int i=0;i< runs;i++)
        points.contains(missing);
    long time = System.nanoTime() - start;
    System.out.printf("Average contains() took %.1f us%n", time/runs/1000.0);
    

    打印

    Average contains() took 5.1 us
    

    您可能需要针对您的数据类型对此进行测试,因为 equals() 的时间和队列的大小可能会有所不同,但您可能会惊讶于您可以在 10 微秒内完成什么,而且这可能已经足够快了。

    【讨论】:

    • 搜索队列所需的时间很大程度上取决于内容的相等方法的性能。抱歉,您不可能为这样的操作估计“小于”任何值。
    • 非常感谢您的回复。我想我会尝试使用这两个集合。我认为开销是值得的,因为元素的数量可能非常大。 :)
    • @jarnbjo 我用“应该”这个词来表示,你应该知道你的 equals 方法的成本是多少,即它不是 RMI 调用,你应该尝试通过首先比较最有可能不同的领域。可能你的 equals 方法调得不好,并且无法访问 equals 方法的功能,但这不是理想的情况。
    猜你喜欢
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多