我需要创建一个类Persistent队列,其中函数enqueue将元素排入当前队列并返回新队列。原始队列如何保持不变。类似地,dequeue函数删除前面元素,返回新队列,但原始队列保持不变。这当然可以在O(队列长度)中完成,但我可以更快地完成。??
答案 0 :(得分:2)
您可以使用链接列表作为队列(不是LinkedList,而是您自己的实现)。
要添加新元素,您只需创建队列类的新实例,将其start元素设置为复制队列的start元素,然后创建新的end元素。
删除元素类似,但将新队列的结束元素设置为复制队列的倒数第二个元素。
队列类可能如下所示:
static class Node {
final Node next;
final Object o;
Node(Node next, Object o) {...}
}
final Node start, end;
private Queue(Node start, Node end) {...}
public Queue(Object o) {
start = end = new Node(null, o);
}
public Queue add(Object o) {
return new Queue(start, new Node(end, o));
}
public Queue remove() {
return new Queue(start, end.next);
}
此队列的add
和remove
方法的复杂性为O(1)。
请注意,您只能以相反的顺序迭代此队列(即首先是最新的元素)。也许你可以想出一些可以反过来甚至两个方向迭代的东西。
答案 1 :(得分:2)
我建议看看scala的实现。该课程顶部的注释描述了所选择的方法(复杂性:O(1)
)。
Queue
实现为一对List
s,其中一个包含''in''元素,另一个包含'out'元素。
元素将添加到“输入”列表中,并从“输出”列表中删除。当''out''列表运行干涸时, 通过将''out''列表替换为'in.reverse''和''in''''''Nil''来转移队列。
将项目添加到队列中的成本始终为O(1)
。除案例外,删除项目的费用为O(1)
需要透视的地方,在这种情况下,会产生O(n)
的成本,其中n
是队列中元素的数量。当这个情况发生时, 保证以n
费用删除O(1)
次删除操作。删除项目的平均值为O(1)
。
答案 2 :(得分:0)
我所做的是使用Java Chronicle(免责声明:我写的)。这是一个无限制的关闭堆持久队列,存储在磁盘或tmpfs(共享内存)上。
在这种方法中,您的消费者会记录队列中的位置,但实际上没有删除任何条目(除了每日或每周维护周期)
这样就可以避免在添加队列时更改队列,而且不需要复制队列。
因此,维护对每个消费者认为的位置的多个引用,对于每个消费者来说,队列的尾部是O(1)。
由于Chronicle使用紧凑的二进制形式,因此您可以存储的数量限制受磁盘空间的限制。例如在必须轮换队列日志之前,2 TB驱动器甚至可以在8 GB的机器上存储这么多数据。