Java集合框架中常见方法(大小)的意外复杂性?

Java集合框架中常见方法(大小)的意外复杂性?,java,data-structures,collections,size,complexity-theory,Java,Data Structures,Collections,Size,Complexity Theory,最近,我对一些Java集合没有方法size()的常量时间操作感到惊讶 虽然我了解到集合的并发实现为获得并发性(ConcurrentLinkedQueue、ConcurrentSkipListSet、LinkedTransferQueue等中的大小为O(n))做出了一些折衷,但好消息是,API文档中正确地记录了这一点 我关心的是某些集合的方法返回的视图的方法大小的性能。例如,返回其元素大于或等于fromElement的支持集部分的视图。令我惊讶的是,返回的SortedSet上的调用大小在时间上是线

最近,我对一些Java集合没有方法size()的常量时间操作感到惊讶

虽然我了解到集合的并发实现为获得并发性(ConcurrentLinkedQueue、ConcurrentSkipListSet、LinkedTransferQueue等中的大小为O(n))做出了一些折衷,但好消息是,API文档中正确地记录了这一点

我关心的是某些集合的方法返回的视图的方法大小的性能。例如,返回其元素大于或等于fromElement的支持集部分的视图。令我惊讶的是,返回的SortedSet上的调用大小在时间上是线性的,即O(n)。至少我从OpenJDK的源代码中找到了这一点: 在TreeSet中,它是作为TreeMap上的包装器实现的,在TreeMap中,有一个EntrySetView类,其大小方法如下:

abstract class EntrySetView extends AbstractSet<Map.Entry<K,V>> {
    private transient int size = -1, sizeModCount;

    public int size() {
        if (fromStart && toEnd)
            return m.size();
        if (size == -1 || sizeModCount != m.modCount) {
            sizeModCount = m.modCount;
            size = 0;
            Iterator i = iterator();
            while (i.hasNext()) {
                size++;
                i.next();
            }
        }
        return size;
    }

    ....
}
抽象类EntrySetView扩展了抽象集{
私有瞬态int size=-1,sizeModCount;
公共整数大小(){
如果(从开始和结束)
返回m.size();
if(size==-1 | | sizeModCount!=m.modCount){
sizeModCount=m.modCount;
尺寸=0;
迭代器i=迭代器();
while(i.hasNext()){
大小++;
i、 next();
}
}
返回大小;
}
....
}
这意味着第一次调用的大小是O(n),然后只要不修改备份映射,它就会被缓存。我在API文档中找不到这个事实。更有效的实现是O(logn),在缓存子树大小时进行内存折衷。由于这样的折衷是为了避免代码重复(TreeSet作为TreeMap上的包装器),我看不出为什么出于性能原因不应该这样做

不管我对TreeSet的OpenJDK实现的(非常简短的)分析是对是错,我想知道是否有一份关于许多此类操作(尤其是完全出乎意料的操作)性能的详细完整的文档

例如,
TreeSet.tailSet
返回其元素大于或等于
fromement
的支持集部分的视图。让我非常惊讶的是,在返回的
SortedSet
上调用
size
在时间上是线性的,即
O(n)

对我来说这并不奇怪。从JavaDoc中考虑这个句子:

此集合支持返回的集合,因此返回集合中的更改将反映在此集合中,反之亦然

由于尾集是支持集的动态视图,因此在实践中必须动态计算其大小。另一种选择是,当对背衬进行更改时,必须调整所有现存尾衬(和耳机)视图的尺寸。这将使备份集的更新成本更高,并且会带来存储管理问题。(为了更新视图大小,备份集需要引用所有现有的视图集…这是一个潜在的隐藏内存泄漏。)

现在,您确实对文档有了一点看法。但事实上,javadocs并没有提到视图集合的复杂性。事实上,它甚至没有记录
TreeSet.size()
O(1)
!实际上,它只记录了
添加
删除
包含
操作的复杂性


我想知道,是否有一份详细完整的文件记录了许多此类操作的执行情况,尤其是那些完全出乎意料的操作


好的,不。当然,不是来自太阳报/甲骨文

我认为Javadocs包含了这些信息。我无法在文档方面提供帮助(我没有看到明确记录的复杂性)。然而,我个人认为
tailSet()
的行为非常直观。我认为更令人惊讶的是,期望每个人都支付内存损失,这样一个边际用例就会有更好的性能。@NPE您是否同意我们所有人都有的内存损失,将每个集合实现为Map的包装器,只是为了JDK开发人员不必两次实现相同的功能?:)我想我已经说得很清楚了,我的问题是文档,而不是性能本身。让我困惑的是TreeMap.size是O(1),TreeMap.tailSet是O(logn),没有关于TreeMap.tailSet().size()的信息,我知道它可以是O(logn)和O(N).我确实理解所有这些,但事实是,有不同的方法,所有方法都有不同的权衡,并且没有记录在选择哪种方法的任何地方。@mario-是的,但我不是投诉的正确人选。(是的,从我坐的地方……你在抱怨。)