簡體   English   中英

Java Collections Framework中常見方法(大小)的意外復雜性?

[英]Unexpected complexity of common methods (size) in Java Collections Framework?

最近,我對一些Java集合沒有方法size()的常量時間操作感到驚訝。

雖然我了解到集合的並發實現作為並發增益(在ConcurrentLinkedQueue中的大小為O(n),ConcurrentSkipListSet,LinkedTransferQueue等)的權衡取得了一些妥協,但好消息是這在API文檔中有適當的記錄。

關注我的是某些集合方法返回的視圖的方法大小的性能。 例如, TreeSet.tailSet返回其元素大於或等於fromElement的支持集部分的視圖。 讓我感到驚訝的是,返回的SortedSet上的調用大小在時間上是線性的,即O(n)。 至少這是我設法從OpenJDK的源代碼中挖掘出來的:在TreeSet中實現為TreeMap的包裝器,在TreeMap中,有一個EntrySetView類,其size方法如下:

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;
    }

    ....
}

這意味着第一次調用大小是O(n),然后只要不修改后備映射就會緩存它。 我無法在API文檔中找到這個事實。 更有效的實現將是O(log n),其中在子樹大小的緩存中具有存儲器權衡。 由於這種權衡是為了避免代碼重復(TreeSet作為TreeMap的包裝器),我沒有看到為什么不應該出於性能原因而制作它們的原因。

無視我對TreeSet的OpenJDK實現的(非常簡短的)分析是對還是錯,我想知道是否有關於許多此類操作的性能的詳細而完整的文檔,尤其是那些完全出乎意料的操作?

例如, TreeSet.tailSet返回其元素大於或等於fromElement的支持集部分的視圖。 讓我感到驚訝的是,返回的SortedSet上的調用size在時間上是線性的,即O(n)

對我來說這並不奇怪。 考慮來自javadoc的這句話:

“返回的集合由此集合支持,因此返回集合中的更改將反映在此集合中,反之亦然。”

由於尾部集是背襯集的動態視圖,因此必須在實踐中動態計算其大小。 替代方案將要求在對支持集進行更改時,必須調整所有現存的尾部(和耳機)視圖的大小。 這將使支持集的更新更加昂貴,並且會出現存儲管理問題。 (為了更新視圖大小,后台集需要引用所有現有視圖集......這可能是隱藏的內存泄漏。)

現在你對文檔有一點看法。 但實際上,javadocs沒有說明視圖集的復雜性。 事實上,它甚至沒有記錄TreeSet.size()O(1) 實際上,它只記錄了addremovecontains操作的復雜性。


我想知道是否有關於許多此類操作的性能的詳細而完整的文檔,尤其是那些完全出乎意料的操作?

AFAIK,不。當然,不是來自Sun / Oracle ......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM