Java 没有复制开销的ArrayList?
有人知道有一个实现具有恒定的时间get(int-index)(即implements),但在它增长时不必复制整个列表吗 我认为实施很可能是在其他列表方面,例如Java 没有复制开销的ArrayList?,java,algorithm,arrays,list,Java,Algorithm,Arrays,List,有人知道有一个实现具有恒定的时间get(int-index)(即implements),但在它增长时不必复制整个列表吗 我认为实施很可能是在其他列表方面,例如 public class ChunkedList<T> implements List<T>, RandomAccess { private LinkedList<ArrayList<T>> chunks; public T get(int index) { return f
public class ChunkedList<T> implements List<T>, RandomAccess {
private LinkedList<ArrayList<T>> chunks;
public T get(int index) {
return findCorrectChunk(index).get(computeChunkIndex(index));
}
}
public类ChunkedList实现列表、随机访问{
私有链接列表块;
公共T获取(整数索引){
返回findCorrectChunk(index).get(computeChunkIndex(index));
}
}
嗯,这并不是一个理想的解决方案,但您可以使用TreeMap来实现这一点。你的ChunkedList将是围绕这一点的一个警告。树映射中的键将是Integer或Long类型,并将保存列表索引。访问和插入时间将是o(log(n))(不是常数,但比n好得多)。在内部,TreeMap的工作原理与LinkedList类似,即节点仅与引用链接
编辑:类似的内容:
public class ChunkedList<T> implements List<T>, RandomAccess {
private TreeMap<Integer, T> data = new TreeMap<Integer, T>();
public T get(int index) {
return data.get(index);
}
public boolean add(T o) {
data.put(data.size() + 1, o);
return true;
}
// Other operations
}
public类ChunkedList实现列表、随机访问{
私有树映射数据=新树映射();
公共T获取(整数索引){
返回数据。获取(索引);
}
公共布尔加法(TO){
data.put(data.size()+1,o);
返回true;
}
//其他业务
}
当然,与ArrayList中的操作相比,其他操作会稍微复杂一些,并且需要更长的时间。如果有这样的结构,每个人都会使用它而不是数组 然而,我认为一个更紧密的结构,我在一次大学演讲中被告知。它有一个恒定的访问时间,向任意位置添加/删除元素的时间主要是O(sqrt(N)),只有当N与整数值的平方相交时,才需要O(N)。摊销时间为O(sqrt(N))。这是我的想法 此结构中的N个项存储在一个连续数组中,该数组被划分为sqrt(N)个连续元素的sqrt(N)块(可能最后一个块包含较少的元素)。每个块都是一个数组,第一个元素的位置存储在一个单独的sqrt(N)数组中。要访问一个元素,您应该确定它所在的块(需要一个除法),并在环形缓冲区内进行适当的移位(求和和和模)。这是一个固定的访问时间 要在第i个位置之前添加元素,请确定元素将结束的块
k
,然后在k
范围内标记每个块中的所有最后元素。sqrt(N)-1
。将pre-last chunk中标记的元素移动到最后一个chunk中的空闲插槽,该插槽将是该区块中环形缓冲区的头部(访问其他数组以确定确切位置)。然后将标记的元素从pre-last chunk移动到从pre-last chunk移动的元素的位置。重复这个,你会在数组中间得到一个空闲的插槽来放置你要添加的元素。
神奇的是,您应该只将额外数组中的值增加一(需要O(sqrt(N))时间),从而使结构一致,以便再次访问。sqrt(N)的魔力也在这里:您应该对辅助数组的每个X块和每个N/X元素进行操作。对于X=sqrt(N),达到最小值(X+N/X)
如果最后一个块中没有地方再添加一个元素(,即到目前为止使用的sqrt(N)太小),请使用增加1的sqrt(N)重新打包数组。这需要O(N)个时间。每个元素的摊销时间仍然为O(sqrt(N))
因此,在数组的任意位置添加元素需要O(sqrt(N))。删除需要相同的时间。访问时间为0(1)
这就是我的想法。我不知道它叫什么,教授也不知道,因为这是他自己发明的。如有任何参考,将不胜感激。OP可以实现它,但我敢打赌,已经有人实现了。当然,您可以将列表实现编写为数组数组。关于精确的算法有很多选择。性能在理论上是恒定的(忽略缓存效果等) 实际上,在大多数情况下没有太多的意义。有rope实现(字符串形成为段数组),但是这些实现相对较少。拷贝并没有那么贵,对于附件来说,它是在许多操作中摊销的,以便消失
(顺便说一句,在问题示例代码中,
LinkedList
几乎总是不合适的。)您是否只考虑过向ArrayList构造函数暗示最大大小?查看一下随机访问列表。您可以在两端获得O(1)插入和O(log(n))对元素的访问
最后,某种类似树的结构应该提供最佳的查找/插入时间。这听起来像是过早的优化。您是否分析了
add()
函数并显示它很慢?因为ArrayList
每当底层数组耗尽空间时,它的大小都会翻倍,所以不必每次追加时都复制列表
您可能正在尝试解决一个不存在的问题。编写这样的数据结构是不可能的。最接近的方法是在已知最大值的情况下,将ArrayList的大小预先设置为最大值。有趣的是,Collections.sort()等算法在
ChunkedList
上的性能将更差,如果其标记为RandomAccess
那么,您有一个列表,需要定期扩展列表并按索引从中删除元素?好的,ArrayList在超出其当前容量时会将其容量加倍。因此将有O(log(n))个拷贝,其中n是列表的最终容量。这意味着需要复制整个列表的实际次数确实非常少。在开销变得显著之前,您可能早就开始耗尽内存了。OTOH,如果您必须停止复制并提前知道列表必须包含的元素数的上限,那么您可以将max size作为参数传递给ArrayL