Java 在端点和元素之前/之后以恒定时间插入的数据结构?

Java 在端点和元素之前/之后以恒定时间插入的数据结构?,java,performance,list,Java,Performance,List,我正在寻找一种数据结构: 具有无限大小 保持其元素的插入顺序 在列表的开头和结尾有效地插入(理想情况下为固定时间) 在现有元素之前或之后有效地插入(理想情况下为固定时间) 我排除了ArrayList,因为它不能有效地插入列表的开头 表面上看,LinkedList应该是一个完美的匹配,但实际上Java实现在现有元素之前或之后插入元素时效率不高(即,它遍历整个列表以找到插入位置) (我个人不需要存储重复的元素,但其他人可能需要) 动机:我正在构建一个允许偶尔作弊的事件队列(在现有事件之前或之后

我正在寻找一种数据结构:

  • 具有无限大小
  • 保持其元素的插入顺序
  • 在列表的开头和结尾有效地插入(理想情况下为固定时间)
  • 在现有元素之前或之后有效地插入(理想情况下为固定时间)
我排除了
ArrayList
,因为它不能有效地插入列表的开头

表面上看,
LinkedList
应该是一个完美的匹配,但实际上Java实现在现有元素之前或之后插入元素时效率不高(即,它遍历整个列表以找到插入位置)

(我个人不需要存储重复的元素,但其他人可能需要)



动机:我正在构建一个允许偶尔作弊的事件队列(在现有事件之前或之后插入)。

AVL树如何?因为树总是平衡的,所以它的高度为O(log(N)),其中N是树中的节点数。这将是最坏的情况 还插入O(log(N))


我相信对于你所寻找的东西来说,这是尽可能接近恒定的时间。很抱歉,如果这不是答案,我的声誉还不够高,无法发表评论://

老实说,我认为定制
LinkedList
将是一种不错的选择:

  • 具有无限大小。
  • 保持其元素的插入顺序。
  • 在列表的开头和结尾有效地插入(理想情况下为固定时间)。
    • 是的,和O(1)
  • 在现有元素之前或之后有效地插入(理想情况下为固定时间)。

    • 如果您维护
      Map我通常使用c++11的
      forward\u list
      来执行需要在任何位置进行最佳插入的操作。它基于单链表。看

      转发列表是序列容器,允许在序列中的任何位置执行固定时间的插入和擦除操作。请参阅

      <>如果优化是你的问题,为什么不切换到C++。我不确定java中是否存在这样的功能。请注意,尽管forward_list提供了固定时间插入,但不能通过位置直接访问图元

      通常对于链表来说,当你说在某个位置插入时。 有两种情况:

    • 在该位置有对节点的引用。在这种情况下,时间复杂度为O(1)

    • 你只有索引。时间复杂度为O(n)

    • 我正在构建一个允许偶尔作弊的事件队列(在现有事件之前或之后插入)

      如果作弊很少,那就选择你自己的基于数组的结构<代码> java .UTI.ArrayDeque < /C>处理O(1)中的两端,但不能在中间插入。它们可以很容易地添加,但复杂度为O(n)

      请注意,
      LinkedList
      对于大多数操作来说(由于其糟糕的数据位置)要比
      ArrayList
      ArrayDeque
      慢得多


      让我们假设,你非常需要在中间插入恒定的时间。差不多

      insertAfter(existingElement, newElement);
      
      java.util.LinkedList的问题在于它没有这样的操作。它所拥有的是 ListItter:,它允许你在中间插入,但是只有当你先定位你的迭代器(O(n))时才有帮助。
      所以你需要你自己的链表。基本实现相当简单,您还需要直接访问其节点(包含
      next
      prev
      链接的内容,而不是
      添加的内容)。然后维护一个
      映射
      ,它允许您查找
      现有元素
      的节点。现在您只需为
      新元素创建一个新节点
      ,将其正确链接(这基本上是微不足道的,但有一些特殊情况)并更新地图


      要消除边界情况(第一个/最后一个/唯一的节点),请将两个虚拟节点(
      prefirst
      postlast
      )添加到链接列表中。显然,这些是唯一不会存储在地图中的节点。它们使实现变得非常简单,例如

      void insertAfter(MyThing existingElement, MyThing newElement) {
         Node found = map.get(existingElement);
         if (found == null) throw ...
         Node newNode = new Node(newElement);
         map.put(newElement, newNode);
      
         // Link newNode where it belongs to.
         newNode.next = found.next;
         newNode.prev = found;
      
         // Fix links.
         newNode.prev.next = newNode;
         newNode.next.prev = newNode;   
      }
      
      void insertFirst(MyThing newElement) {
         Node found = prefirst;
      
         // All the remaining code is simply copied from above.
         // Factor it out.
      
         Node newNode = new Node(newElement);
         map.put(newElement, newNode);
      
         // Link newNode where it belongs to.
         newNode.next = found.next;
         newNode.prev = found;
      
         // Fix links.
         newNode.prev.next = newNode;
         newNode.next.prev = newNode;   
      }
      
      使用

      • 保留插入顺序
      • 很快(因为使用键基本上在
        O(1)
        中查找元素)
      • 允许您随时插入元素(但为此,您需要考虑一个好的键-设计一个对您的排序逻辑有意义的
        hashCode()
        equals()
      哈希表和链表映射接口的实现,带 可预测的迭代顺序。此实现不同于HashMap 因为它维护了一个贯穿其所有应用程序的双链接列表 条目。此链表定义迭代顺序,即 通常是将关键点插入地图的顺序 (插入顺序)

      我会反对定制收集,因为你会花很多时间重新发明轮子,然后你最终会得出结论,使用
      LinkedHashMap
      更好


      请注意,此集合不是线程安全的。

      LinkedHashMap?@ACV如何在现有元素之前或之后插入?取决于在给定要插入的元素之前/之后如何检测要插入的“现有元素”。允许重复吗?@user7是的,正如khachik所说,您需要首先定义一个好的键,这样才能工作
      O(log(N))
      不是常量time@user7OP说“理想的恒定时间”,这就是为什么我说“尽可能接近您所寻找的恒定时间。”如果可以的话,我会把它作为一条评论:/无论如何,我更喜欢答案而不是评论。是否有针对Java的已建立的AVL树实现?这也无法维护的插入顺序