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的
来执行需要在任何位置进行最佳插入的操作。它基于单链表。看 转发列表是序列容器,允许在序列中的任何位置执行固定时间的插入和擦除操作。请参阅 <>如果优化是你的问题,为什么不切换到C++。我不确定java中是否存在这样的功能。请注意,尽管forward_list提供了固定时间插入,但不能通过位置直接访问图元 通常对于链表来说,当你说在某个位置插入时。 有两种情况:forward\u 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()
更好LinkedHashMap
请注意,此集合不是线程安全的。LinkedHashMap?@ACV如何在现有元素之前或之后插入?取决于在给定要插入的元素之前/之后如何检测要插入的“现有元素”。允许重复吗?@user7是的,正如khachik所说,您需要首先定义一个好的键,这样才能工作
不是常量time@user7OP说“理想的恒定时间”,这就是为什么我说“尽可能接近您所寻找的恒定时间。”如果可以的话,我会把它作为一条评论:/无论如何,我更喜欢答案而不是评论。是否有针对Java的已建立的AVL树实现?这也无法维护的插入顺序O(log(N))
- 如果您维护