概要:
ArrayListのトラバーサルスルーforは、イテレーターのトラバーサルよりもわずかに高速です。LinkedListのイテレータートラバーサルは、トラバーサルスルーforよりも高速です。
したがって、このアプリケーションでは、実際のシーンのニーズをより適切に満たすことができる、使用するListインターフェイスの実装クラスを検討する必要があります。したがって、ここでは、RandomAccessインターフェイスを実装して、Listの実装クラスを区別します。
私たちの開発では、Listインターフェースが最も一般的で、ほぼ毎日ArrayListまたはLinkedListを使用していますが、注意深い学生にRandomAccessインターフェースがArrayListに実装されているのに、LinkedListがRandomAccessインターフェースを実装していないことを知ってもらいます。なぜですか。 ?
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
RandomAccessインターフェースは空です。RandomAccessインターフェースとは何ですか?
public interface RandomAccess {
}
RandomAccessインターフェース
RandomAccessはマーカーインターフェイスです。公式の説明では、Listがこのインターフェイスを実装している限り、高速ランダムアクセスをサポートできます。そして、ランダムアクセスとは何ですか?例を見てみましょう。
コレクションはコレクションのツールクラスです。コレクションソースコードのバイナリ検索メソッドを見てみましょう。
public static <T>
int binarySearch(List<? extends Comparable<? super T>> list, T key) {
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else
return Collections.iteratorBinarySearch(list, key);
}
ソースコードからわかるように、リストがRandomAccessのインスタンスであるかどうかが判断され、インスタンスである場合はindexedBinarySearchメソッドが実行され、そうでない場合はiteratorBinarySearchメソッドが実行されます。次に、これら2つの方法を見てみましょう。
private static <T> int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) { int low = 0; int high = list.size()-1;
while (low <= high) { int mid = (low + high) >>> 1; Comparable<? super T> midVal = list.get(mid); int cmp = midVal.compareTo(key); if (cmp < 0) low = mid + 1; else if (cmp > 0) high = mid - 1; else return mid; // key found } return -(low + 1); // key not found
}
private static <T>
int iteratorBinarySearch(List <?extends Comparable <?super T >> list、T key)
{ int low = 0; int high = list.size()-1; ListIterator <?Comparable <?スーパーT >> i = list.listIterator();
while (low <= high) {
int mid = (low + high) >>> 1;
Comparable<? super T> midVal = get(i, mid);
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
上記の2つのメソッドのソースコードは、RandomAccessインターフェイスを実装するリストがインデックストラバーサルを使用するのに対し、RandomAccessインターフェイスを実装しないリストはイテレータトラバーサルを使用することを示しています。では、なぜこのように設計されているのでしょうか。
二分探索のトラバーサル操作が含まれているので、次にArrayListおよびLinkedListトラバーシング要素のパフォーマンスを分析しましょう。
public class CollectionTest { public static void main(String[] args){ long arrayListIndexedTime = arrayListIndexed(); long arrayListIteratorTime = arrayListIterator(); long linkedListIndexedTime = linkedListIndexed(); long linkedListIteratorTime = linkedListIterator(); System.out.println("测试ArrayList通过for遍历所消耗时间:" + arrayListIndexedTime); System.out.println("测试ArrayList通过iterator遍历所消耗时间:" + arrayListIteratorTime); System.out.println("测试LinkedList通过for遍历所消耗时间:" + linkedListIndexedTime); System.out.println("测试LinkedList通过iterator遍历所消耗时间:" + linkedListIteratorTime); }
//测试ArrayList通过for遍历所消耗时间 public static long arrayListIndexed() { List<Integer> arrayList = new ArrayList<>(); for (int i = 0; i < 10000; i++) { arrayList.add(i); } //记录开始时间 long startTime = System.currentTimeMillis(); for (int i = 0; i < arrayList.size(); i++) { arrayList.get(i); } //记录结束时间 long endTime = System.currentTimeMillis(); //遍历消耗时间 long resultTime = endTime - startTime; return resultTime; } //测试ArrayList通过iterator遍历所消耗时间 public static long arrayListIterator() { List<Integer> arrayList = new ArrayList<>(); for (int i = 0; i < 10000; i++) { arrayList.add(i); } //记录开始时间 long startTime = System.currentTimeMillis(); Iterator<Integer> iterator = arrayList.iterator(); while (iterator.hasNext()) { iterator.next(); } //记录结束时间 long endTime = System.currentTimeMillis(); //遍历消耗时间 long resultTime = endTime - startTime; return resultTime; } //测试LinkedList通过for遍历所消耗时间 public static long linkedListIndexed() { List<Integer> linkedList = new LinkedList<>(); for (int i = 0; i < 10000; i++) { linkedList.add(i); } //记录开始时间 long startTime = System.currentTimeMillis(); for (int i = 0; i < linkedList.size(); i++) { linkedList.get(i); } //记录结束时间 long endTime = System.currentTimeMillis(); //遍历消耗时间 long resultTime = endTime - startTime; return resultTime; } //测试LinkedList通过iterator遍历所消耗时间 public static long linkedListIterator() { List<Integer> linkedList = new LinkedList<>(); for (int i = 0; i < 10000; i++) { linkedList.add(i); } //记录开始时间 long startTime = System.currentTimeMillis(); Iterator<Integer> iterator = linkedList.iterator(); while (iterator.hasNext()) { iterator.next(); } //记录结束时间 long endTime = System.currentTimeMillis(); //遍历消耗时间 long resultTime = endTime - startTime; return resultTime; }
}
試験結果は以下のとおりです。
测试ArrayList通过for遍历所消耗时间:1
测试ArrayList通过iterator遍历所消耗时间:2
测试LinkedList通过for遍历所消耗时间:47
测试LinkedList通过iterator遍历所消耗时间:1
テスト結果を分析してみましょう。ArrayListトラバーサルスルーforは、イテレーターを介したトラバーサルよりもわずかに高速であり、LinkedListトラバーサルスルーforは、トラバーサルスルーforよりも高速です。
したがって、このアプリケーションでは、実際のシーンのニーズをより適切に満たすことができる、使用するListインターフェイスの実装クラスを検討する必要があります。したがって、ここでは、RandomAccessインターフェイスを実装して、Listの実装クラスを区別します。
総括する
**
最後に要約文:RandomAccessインターフェイスを実装するリストは、イテレータを使用してデータをトラバースするよりも効率的にforループを介してデータをトラバースできます。RandomAccessインターフェイスを実装しないリストは、forループを使用するよりも効率的にイテレータを介してデータをトラバースできます。データをトラバースします。
****
</div><div><div></div></div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-ff98e99283.css" rel="stylesheet">
</div>
私たちの開発では、Listインターフェースが最も一般的で、ほぼ毎日ArrayListまたはLinkedListを使用していますが、注意深い学生にRandomAccessインターフェースがArrayListに実装されているのに、LinkedListがRandomAccessインターフェースを実装していないことを知ってもらいます。なぜですか。 ?
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
RandomAccessインターフェースは空です。RandomAccessインターフェースとは何ですか?
public interface RandomAccess {
}
RandomAccessインターフェース
RandomAccessはマーカーインターフェイスです。公式の説明では、Listがこのインターフェイスを実装している限り、高速ランダムアクセスをサポートできます。そして、ランダムアクセスとは何ですか?例を見てみましょう。
コレクションはコレクションのツールクラスです。コレクションソースコードのバイナリ検索メソッドを見てみましょう。
public static <T>
int binarySearch(List<? extends Comparable<? super T>> list, T key) {
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else
return Collections.iteratorBinarySearch(list, key);
}
ソースコードからわかるように、リストがRandomAccessのインスタンスであるかどうかが判断され、インスタンスである場合はindexedBinarySearchメソッドが実行され、そうでない場合はiteratorBinarySearchメソッドが実行されます。次に、これら2つの方法を見てみましょう。
private static <T> int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) { int low = 0; int high = list.size()-1;
while (low <= high) { int mid = (low + high) >>> 1; Comparable<? super T> midVal = list.get(mid); int cmp = midVal.compareTo(key); if (cmp < 0) low = mid + 1; else if (cmp > 0) high = mid - 1; else return mid; // key found } return -(low + 1); // key not found