簡體   English   中英

為什么 ArrayList 實現了 RandomAccess 接口?

[英]Why does ArrayList implement RandomAccess Interface?

ArrayList實現了RandomAccess接口。 RandomAccess接口沒有方法。 當我檢查LinkedList它沒有實現RandomAccess接口。

那么在ArrayList情況下,實現它的重點是什么?

沒有方法的接口在 Java 中稱為標記接口。

根據 RandomAccess 的 JavaDoc:

List 實現使用的標記接口來指示
它們支持快速(通常是恆定時間)隨機訪問。

有關更多信息,請查看兩個 JavaDoc 頁面。

http://docs.oracle.com/javase/6/docs/api/java/util/RandomAccess.html

http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html

RandomAccess 接口沒有方法

這稱為標記界面,是一種稱為標記界面模式的設計模式

當我檢查 LinkedList 時,它沒有實現 RandomAccess 接口。 那么在 ArrayList 的情況下,實現它的重點是什么?

因為LinkedList隨機訪問是 O(n),而在ArrayList它是 O(1)。

它在文檔中說明

用於操作隨機訪問列表(如 ArrayList)的最佳算法在應用於順序訪問列表(如 LinkedList)時可以產生二次行為

這似乎在文檔中得到了很好的描述: http : //docs.oracle.com/javase/7/docs/api/java/util/RandomAccess.html

List 實現使用的 RandomAccess Marker 接口來指示它們支持快速(通常是恆定時間)隨機訪問 此接口的主要目的是允許通用算法改變其行為,以在應用於隨機或順序訪問列表時提供良好的性能。 用於操作隨機訪問列表(例如 ArrayList)的最佳算法在應用於順序訪問列表(例如 LinkedList)時可以產生二次行為。 鼓勵通用列表算法在應用算法之前檢查給定列表是否是此接口的實例,如果將其應用於順序訪問列表,則會提供較差的性能,並在必要時更改它們的行為以保證可接受的性能。

人們認識到隨機訪問和順序訪問之間的區別通常是模糊的。 例如,一些 List 實現提供了漸近線性的訪問時間,如果它們變得巨大,但實際上訪問時間是恆定的。 這樣的 List 實現一般應該實現這個接口。 根據經驗,如果對於類的典型實例,這個循環,List 實現應該實現這個接口:

 for (int i=0, n=list.size(); i < n; i++) list.get(i);

運行速度比這個循環快:

 for (Iterator i=list.iterator(); i.hasNext(); ) i.next();

1) 有兩個類實現了RandomAccess接口。 他們是:

ArrayList (Part of List<I>)
Vector    (Part of List<I>)

2) RandomAccess接口的目的是以相同的速度檢索集合中的任何隨機元素。 示例:我有 100 萬個對象的集合。 實現RandomAccess接口使您檢索第 10 個元素和第 17869 個元素的時間相同。 這使得ArrayListVector更加強大。

3) RandomAccess接口沒有方法或字段,也稱為標記接口。 這些用於向編譯器指示某些內容,換句話說,實現這些接口意味着對實現類進行一些特殊處理。

讓我們看看如何實際使用這個標記界面。 首先是文檔中的相關部分(粗體是我的,只是為了強調)。

List 實現使用的標記接口來指示它們支持快速(通常是恆定時間)隨機訪問。 此接口的主要目的是允許通用算法改變其行為,以在應用於隨機或順序訪問列表時提供良好的性能。 List 實現使用的 RandomAccess Marker 接口來指示它們支持快速(通常是恆定時間)隨機訪問。 此接口的主要目的是允許通用算法改變其行為,以在應用於隨機或順序訪問列表時提供良好的性能 用於操作隨機訪問列表(例如 ArrayList)的最佳算法在應用於順序訪問列表(例如 LinkedList)時可以產生二次行為。

讓我們舉個例子。 假設您正在編寫諸如排序之類的算法的通用實現,並且您正在根據需要就地排序選擇快速排序。 為什么是泛型 因為也許你想要的算法,能夠對各種名單的合理性和可預測的性能特性的工作(有許多種在那里-不)。 所以你的算法函數會將一個列表作為輸入並返回與排序相同的列表。 暫時先拋開影響快速排序性能的各種因素(例如已排序的數據、重復的數據、正確選擇樞軸等)。 除了數據/排序的上述特征之外,另一個關鍵點是您的算法使我們大量遍歷列表 - 在這種情況下,它大量使用隨機訪問,因為它需要比較和交換元素。 那么你怎么看 - 你的算法會在所有類型的 List 實現上表現良好。 想想LinkedList - API 中有隨機訪問的規定,但它需要大量的遍歷,因為數據在列表中的組織方式的本質是節點相互指向,以及通過大量節點的痛苦不可避免的行為到達隨機節點。 因此,您的通用算法在性能方面具有更大的可變性。 如果您以某種方式知道某些列表提供快速隨機存取,而有些則不能。 如果有一個這樣的標記怎么辦。 ArrayList 實現了“RandomAccess”標記接口(標記/注釋是更好的詞),以指示(您的代碼通常會使用instanceof RandomAccess 測試進行檢查)隨機訪問它的數據非常快,您可以依賴它編寫一個執行的算法,如果某個列表不執行,則嘗試替代算法,或者可能首先將其轉換為 ArrayList,或者最壞的情況是完全拒絕這樣的輸入。

文檔的另一部分通過提供兩種不同的方式來訪問易於理解的基礎數據來處理被認為是快速隨機的內容。 快速隨機訪問意味着第一個總是比第二個運行得快。

for (int i=0, n=list.size(); i < n; i++)
         list.get(i);

runs faster than this loop:
     for (Iterator i=list.iterator(); i.hasNext(); )
         i.next();

RandomAccess:標記接口

java.util.RandomAccess - 從 JDK 1.4 開始,集合框架的成員。 實現:ArrayList 和 CopyOnWriteArrayList。

對於數據的隨機訪問(索引基礎)

List 實現使用的標記接口來指示它們支持快速(通常是恆定時間)隨機訪問。 此接口的主要目的是允許通用算法改變其行為,以在應用於隨機或順序訪問列表時提供良好的性能。

用於操作隨機訪問列表(例如 ArrayList)的最佳算法在應用於順序訪問列表(例如 LinkedList)時可以產生二次行為。

鼓勵通用列表算法在應用算法之前檢查給定列表是否是此接口的實例,如果將其應用於順序訪問列表,則會提供較差的性能,並在必要時更改它們的行為以保證可接受的性能。

人們認識到隨機訪問和順序訪問之間的區別通常是模糊的。

如果對於類的典型實例,此循環,則 List 實現應實現此接口:

for (int i=0, n=list.size(); i < n; i++)
         list.get(i);

runs faster than this loop:

for (Iterator i=list.iterator(); i.hasNext(); )
         i.next();

有關更多信息,請參閱我的博客:
http://javaexplorer03.blogspot.in/2015/07/randomaccess-java.html

RandomAccess 接口表示對 Collection 元素的高效隨機訪問

在客戶端代碼中,您可以檢查集合是否是 RandomAccess 的實例,然后只執行 Random 訪問操作。

LinkedList 和 ArrayList 中的元素都可以隨機訪問,但是 ArrayList 復雜度為 O(1),LinkedList 為 O(n)。

接口沒有方法(Marker Interface),但是你可以用它來測試一個特定的集合是否支持高效的隨機訪問

Collection<Integer> c = new ArrayList<Integer>();
if (c instanceof RandomAccess)
{
        System.out.println("use random access algorithm -> like ArrayList");//fast access date
}
else
{
        System.out.println("use sequential access algorithm -> like LinkedList");//fast delete data 
}
  1. 標記接口的存在僅僅是它指示(或期望)來自實現類的特定行為。

  2. 所以,在我們的例子中,ArrayList 實現了 RandomAccess 標記接口。

  3. 因此,ArrayList 類的期望是,當客戶端想要訪問某個索引處的某個元素時,它應該對 ArrayList 類的客戶端產生 RandomAccess 行為。

那么,ArrayList 是如何實現這種隨機性的呢?

public E get(int index) {
        rangeCheck(index); // to check for out of bounds index.

        return elementData(index); // another method invocation
    }

E elementData(int index) {
        return (E) elementData[index]; // accesses internal array.
    }

// following is the internal array , used by ArrayList
transient Object[] elementData; // non-private to simplify nested class access
  1. 現在,我們知道 LinkedList 沒有實現 RandomAccess,因此,它不能保證隨機訪問行為。 讓我們也檢查下面的 LinkedList 代碼,注意這里的 for 循環,所以,它是一個順序訪問。 還要觀察按位運算符技巧: size >> 1表示,size 除以 2。因此,它基本上會檢查索引是在前半部分還是后半部分。 如果是在下半場,從結尾開始是有道理的。 這是一個優化,很好的技巧。

    `public E get(int index) { checkElementIndex(index); 返回節點(索引)。項目; }

    節點 node(int index) { // 斷言 isElementIndex(index);

     if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; }

    }`

RandomAccess :此接口在 Java 1.4 版中引入。 它標志着可以隨機訪問的列表的實現。 它存在於java.util.RandomAccess 中

List 實現使用的標記接口來指示它們支持快速隨機訪問。

更准確地說,RandomAccess 接口識別使用 List.get() 方法而不是使用Iterator.next() 方法迭代速度更快的 List 實現

ArrayList 實現了 RandomAccess 接口。 RandomAccess 接口沒有方法。 當我檢查 LinkedList 時,它沒有實現 RandomAccess 接口。

因為 ArrayList 和 Vector 是基於索引的,LinkedList 遵循雙鏈表。

時間復雜度

ArrayList: Java 中的 ArrayList 由一個數組支持。 隨機訪問需要 O(1) 時間

get() – 總是一個常數時間 O(1) 操作

LinkedList LinkedList 是一種線性數據結構,它由保存數據字段的節點和對另一個節點的引用組成。

get() – 搜索元素需要 O(n) 時間。

注意: ArrayList 可以為您提供 O(1) 復雜度的任何元素,因為數組具有隨機訪問屬性。 您可以直接訪問任何索引,而無需遍歷整個數組。

LinkedList 具有順序訪問屬性。 它需要遍歷每個元素才能到達給定的索引,因此從 LinkedList 按索引獲取值的時間復雜度為 O(N)。

暫無
暫無

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

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