集合概述
集合(collection)——有時也被稱作容器, 用來把具有相同性質的一類東西,匯聚成一個整體。Collections被廣泛應用於存儲,獲取及操作數據。
集合框架
集合框架(Collections Framework)是對進行collections表示和操作的統一架構,Java 集合框架包括如下幾個部分:
- 接口: 表示集合的抽象數據類型。接口提供了讓我們對集合中所表示的內容進行單獨操作的可能。在面嚮對象語言中,接口通常以繼承的形式表示。
- 實現: 也就是集合框架中接口的具體實現。實際它們就是那些可複用的數據結構。
- 算法: 在一個實現了某個集合框架中的接口的對象身上完成某種有用的計算的方法,例如查找、排序等。這些算法通常是多態的,因爲相同的方法可以在同一個接口被多個類實現時有不同的表現。
Java集合框架的益處
使用Java 集合框架將給我們帶來如下好處:
- 減少了程序設計的辛勞。集合框架通過提供有用的數據結構和算法使你能集中注意力於你的程序的重要部分上,而不是爲了讓程序能正常運轉而將注意力於低層設計上。通過這些在無關API之間的簡易的互用性,使你免除了爲改編對象或轉換代碼以便聯合這些API而去寫大量的代碼。
- 提高了程序速度和質量。集合框架通過提供對有用的數據結構和算法的高性能和高質量的實現使 你的程序速度和質量得到提高。因爲每個接口的實現是可互換的,所以你的程序可以很容易的通過改變一個實現而進行調整。另外,你將可以從寫你自己的數據結構 的苦差事中解脫出來,從而有更多時間關注於程序其它部分的質量和性能。
- 減少去學習和使用新的API 的辛勞。許多API天生的有對集合的存儲和獲取。在過去,這樣的API都有一些子API幫助操縱它的集合內容,因此在那些特殊的子API之間就會缺乏一致性,你也不得不從零開始學習,並且在使用時也很容易犯錯。而標準集合框架接口的出現使這個問題迎刃而解。
- 減少了設計新API的努力。設計者和實現者不用再在每次創建一種依賴於集合內容的API時重新設計,他們只要使用標準集合框架的接口即可。
- 集合框架鼓勵軟件的複用。對於遵照標準集合框架接口的新的數據結構天生即是可複用的。同樣對於操作一個實現了這些接口的對象的算法也是如此。
接口
集合核心接口(core collection interfaces)包含了多種類型的集合。如下圖所示:
圖表 1:集合核心接口
所有的接口都是泛型接口,聲明形式如下:
public interface Collection<E>...
當創建一個集合實例時,需要指定放入集合的數據類型。指定集合數據類型使得編譯器能檢查放入集合的數據類型是否正確,從而減少運行時錯誤,關於泛型更多知識,請參看泛型相關章節。
Collection接口
Collection
接口是所有集合接口的基類,提供了集合接口的通用操作。其定義如下:
public interface Collection<E> extends Iterable<E> {
// Basic operations
int size();
boolean isEmpty();
boolean contains(Object element);
boolean add(E element); //optional
boolean remove(Object element); //optional
Iterator<E> iterator();
// Bulk operations
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c); //optional
boolean removeAll(Collection<?> c); //optional
boolean retainAll(Collection<?> c); //optional
void clear(); //optional
// Array operations
Object[] toArray();
<T> T[] toArray(T[] a);
}
通過這些操作函數,我們可以進行獲取集合中元素的個數 (size
, isEmpty
),判斷集合中是否包含某個元素(contains
),在集合中增加或刪除元素(add
, remove
),獲取訪問迭代器(iterator
)等操作。
遍歷Collection
有兩種方式可以實現對集合的遍歷:
for-each 循環
for-each
循環能以一種非常簡潔的方式對集合中的元素進行遍歷,如下所示:
for (Object o : collection)
System.out.println(o);
迭代器
迭代器(Iterator
)可以用來遍歷集合並對集合中的元素進行刪操作。
可以通過集合的iterator
函數獲取該集合的迭代器。Iterator
接口如下所示:
public interface Iterator<E> {
boolean hasNext();
E next();
void remove(); //optional
}
當集合中還有元素供迭代器訪問時,hasNext
函數返回true。此時,可以通過next函數返回集合中的下一個元素。
函數remove刪除next()
最後一次
從集合中訪問的元素。
注意:Iterator.remove
是在迭代過程中修改
collection的唯一安全的方法,在迭代期間不允許使用其它的方法對collection進行操作。
下列情況下,需要使用迭代器代替for-each
循環:
·
刪除當前節點:
for-each
隱藏了迭代器,故無法調用remove函數。正因如此,for-each不能用來對集合過濾。
· 在多重集合上進行並行迭代
下列代碼演示瞭如何使用 Iterator
對
Collection
元素過濾(遍歷集合,並刪除特定元素):
static void filter(Collection<?> c) {
for (Iterator<?> it = c.iterator(); it.hasNext(); )
if (!cond(it.next()))
it.remove();
}
Collection的批量操作
集合的批量操作接口函數如下:
containsAll
— 檢查集合中是否包含指定集合addAll
— 在集合中加入指定集合removeAll
— 在集合中刪除包含於指定集合的元素retainAll
—刪除集合中不包含於指定集合的元素clear
— 刪除集合中所有元素
在addAll
, removeAll
及
retainAll
操作中,如果集合的元素被更改,則返回true。
下列代碼演示瞭如何從一個集合中移除所有包含特定值的元素:
c.removeAll(Collections.singleton(e));
另外一個常用的批量操作是移除集合中所有的null元素:
c.removeAll(Collections.singleton(null));
Collection和數組間的轉換
數組轉化爲集合:
List<String> c = new ArrayList<String>(…);
集合轉化爲數組:
String[] a = c.toArray(new String[0]);
Set接口
Set 是一個不包含重複元素的集合(Collection)。Set接口中的函數都是從Collection繼承而來。 但限制了add 的使用,需要其不能添加重複元素。
Set接口聲明如下:
public interface Set<E> extends Collection<E> {
// Basic operations
int size();
boolean isEmpty();
boolean contains(Object element);
boolean add(E element); //optional
boolean remove(Object element); //optional
Iterator<E> iterator();
// Bulk operations
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c); //optional
boolean removeAll(Collection<?> c); //optional
boolean retainAll(Collection<?> c); //optional
void clear(); //optional
// Array Operations
Object[] toArray();
<T> T[] toArray(T[] a);
}
Java平臺中包含了三個通用的Set的實現: HashSet, TreeSet, 和 LinkedHashSet. HashSet通過hash表存儲集合元素。TreeSet通過紅黑數存儲集合元素。LinkedHashSet通過鏈表存儲集合元素。
假如你有一個集合c,並且你想創建一個包含c中所有不重複元素的集合,可以通過如下方式實現:
Collection<Type> noDups = new HashSet<Type>(c);
如果想在新的Set中保留原始集合的順序,可以通過如下方式:
Collection<Type> noDups = new LinkedHashSet<Type>(c);
該操作可以通過泛型函數封裝如下:
public static <E> Set<E> removeDups(Collection<E> c) {
return new LinkedHashSet<E>(c);
}
Set接口基本操作
Set基本操作和Collection類似,這裏就不再累敘
Set的一個基本應用如下所示:
import java.util.*;
public class FindDups {
public static void main(String[] args) {
Set<String> s = new HashSet<String>();
for (String a : args)
if (!s.add(a))
System.out.println("Duplicate detected: " + a);
System.out.println(s.size() + " distinct words: " + s);
}
}
該程序能找出一個字符串中的重複單詞,將其打印出來,並且返回所有不重複的單詞。
運行程序,
java FindDups i came i saw i left
輸出結果如下:
Duplicate detected: i
Duplicate detected: i
4 distinct words: [i, left, saw, came]
Set接口批量操作
Set的批量操作和離散數學的集合操作的概論結合的非常好,假如s1和s2是兩個Set,它們間的批量操作如下:
s1.containsAll(s2) —
判斷s2是否是s1的子集
s1.addAll(s2) —
將s1轉化爲s1和s2的並集
s1.retainAll(s2) —
將s1轉化爲s1和s2的交集
s1.removeAll(s2) —
將s1轉化爲s1和s2的差集
我們來繼續看一下前面的FindDups程序。這次我們需要知道那些單詞重複出現過,哪些單詞只出現過一次,可以修改程序爲如下所示:
import java.util.*;
public class FindDups2 {
public static void main(String[] args) {
Set<String> uniques = new HashSet<String>();
Set<String> dups = new HashSet<String>();
for (String a : args)
if (!uniques.add(a))
dups.add(a);
// Destructive set-difference
uniques.removeAll(dups);
System.out.println("Unique words: " + uniques);
System.out.println("Duplicate words: " + dups);
}
}
輸入和前面同樣的參數(i came i saw i left),輸出結果如下:
Unique words: [left, saw, came]
Duplicate words: [i]
Set和數組間的轉換
Set和數組間的轉換和Collection和數組間的轉換一致,請參看前面相關章節。
List接口
List是一個順序的Collection(通常被稱作序列)。List可以包含重複元素。List接口基本功能如下:
按位置訪問 — 通過元素在list中的位置索引訪問元素。
查詢 — 獲取某元素在list中的位置
迭代 — 擴展了Iterator的接口能實現更多功能
List
子集合 — 獲取List某個位置範圍的子集合
List接口如下:
public interface List<E> extends Collection<E> {
// Positional access
E get(int index);
E set(int index, E element); //optional
boolean add(E element); //optional
void add(int index, E element); //optional
E remove(int index); //optional
boolean addAll(int index,
Collection<? extends E> c); //optional
// Search
int indexOf(Object o);
int lastIndexOf(Object o);
// Iteration
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
// Range-view
List<E> subList(int from, int to);
}
Java平臺中包含了兩個泛型的List的實現:ArrayList和LinkedList。
List與Vector有許多相似之處。List對Vector的一些常用的Api進行了改進,使之更加簡單易用。
對於如下元素賦值操作:
a[i] = a[j].times(a[k]);
Vector:v.setElementAt(v.elementAt(j).times(v.elementAt(k)), i);
List:v.set(i, v.get(j).times(v.get(k)));
可以看到,List的元素的獲取和設置操作比Vector的更加簡潔。
此外,List的add(int, E)對應與Vector的insertElementAt(Object, int)操作,用subList操作統一代替了Vector的indexOf, lastIndexOf和setSize三個操作。
List接口基本操作
List接口實現了所有Collection接口定義的功能,這裏就不再累述。
另外,可以通過addAll和inserts進行元素的批量插入操作。
和Set接口一樣,List接口增強了兩個函數:equals 和hashCode。用以實現比較兩個List是否相等(在相同的位置包含相同的元素)。
按位置訪問的操作有:get, set, add 和 remove。這些和Vector的相關方法的功能基本一致。
查詢操作可以通過indexOf函數返回某元素在List的索引位置信息。
List迭代器
List提供了更加強大的迭代器,能夠在迭代過程中能夠進行進行添加及修改操作,獲取當前位置信息等。ListIterator接口定義如下:
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
void remove(); //optional
void set(E e); //optional
void add(E e); //optional
}
該接口中有三個函數繼承自Iterator (hasNext, next, and remove),並且實現同樣的功能。hasPrevious和previous函數使用方式和hasNext和next類似,通過它們組合使用可以實現向前迭代,方式如下:
for (ListIterator<Type> it = list.listIterator(list.size());
it.hasPrevious(); ) {
Type t = it.previous();
...
}
注意listIterator的構造方式,List提供兩個函數用來構造listIterator。listIterator()函數返回list起始位置的迭代器,listIterator(index)函數返回list某個位置的迭代器,若某個list的長度爲n,則index的取值範圍爲0到n,如下圖所示:
圖表 2: 迭代器遊標位置
List子集合操作
通過subList(int fromIndex, int toIndex)函數能獲取List某個範圍的子集合,其中[romIndex, toIndex)是一個左閉右開的半開區間,類似for循環中的區間方式:
for (int i = fromIndex; i < toIndex; i++) {
...
}
由於List子集也是一個List,任何作用與List的操作同樣也可以作用與List子集。
List算法
大多數集合算法可以應用於List的,通過這些算法,可以快速有效的實現List的相關操作。常用操作如下:
sort —
通過歸併排序(merge sort)算法對List進行快速,可靠的排序。
shuffle —
對List中的元素進行隨機放置
reverse —
對List進行逆序操作
rotate — rotates all the elements in a List by a specified distance.
swap —
交換List中的特定位置的元素
replaceAll —
替換所有滿足特定條件的元素
fill — overwrites every element in a List with the specified value.
copy —
實現對源List和目標List的數據拷貝
binarySearch —
使用二分查找算法查詢List中的元素(List已經排序)
indexOfSubList —
返回某元素在Sub子集中的位置信息
Queue接口
Queue 是一種保證元素處理順序(通常是FIFO,但不一定)的集合。除了基本的集合操作外,Queue還提供了自己的插入,訪問及刪除元素的操作。Queue接口如下所示:
public interface Queue<E> extends Collection<E> {
E element();
boolean offer(E e);
E peek();
E poll();
E remove();
}
Queue函數操作失敗有兩種處理方式:(1)拋出異常 (2) 返回失敗碼 (通常是null或false)。下表顯示了常用操作的失敗處理方式:
Queue Interface Structure |
||
|
Throws exception |
Returns special value |
Insert |
add(e) |
offer(e) |
Remove |
remove() |
poll() |
Examine |
element() |
peek() |
bounded是一種可以限制元素的數目Queue。java.util.concurrent中定義了一些bounded的實現,java.util中的Queue的實現都不是bounded。
在Queue中插入元素可以通過add函數(繼承自Collection)和inserts函數進行,它們的區別是出錯時的處理方式不同。
訪問Queue中的元素可以通過remove函數(繼承自Collection)和poll函數進行,它們的區別是出錯時的處理方式不同。
此外,也可以通過element函數(繼承自Collection)和peek函數訪問Queue中的元素,它們的區別是出錯時的處理方式不同。與remove和poll函數不同的是,它們訪問Queue後並不刪除Queue的元素。
Queue 實現通常通常不允許插入null元素,但LinkedList(實現了Queue接口)卻是個例外(由於某些歷史原因)。但在使用過程中,應儘量避免將null插入到其中,因爲它也是元素訪問函數poll和peek執行失敗的返回值。
Queue接口中定義的方法都不是阻塞式的,如果要使用阻塞式的Queue,請使用java.util.concurrent.BlockingQueue接口的相應實現類。
下列代碼演示了一個Queue作爲計時器的應用:
import java.util.*;
public class Countdown {
public static void main(String[] args)
throws InterruptedException {
int time = Integer.parseInt(args[0]);
Queue<Integer> queue = new LinkedList<Integer>();
for (int i = time; i >= 0; i--)
queue.add(i);
while (!queue.isEmpty()) {
System.out.println(queue.remove());
Thread.sleep(1000);
}
}
}
Map接口
Map 是一種包含鍵值對的元素的集合。Map不能包含重複的鍵,並可通過鍵實現對值的快速訪問。Map接口如下所示:
public interface Map<K,V> {
// Basic operations
V put(K key, V value);
V get(Object key);
V remove(Object key);
boolean containsKey(Object key);
boolean containsValue(Object value);
int size();
boolean isEmpty();
// Bulk operations
void putAll(Map<? extends K, ? extends V> m);
void clear();
// Collection Views
public Set<K> keySet();
public Collection<V> values();
public Set<Map.Entry<K,V>> entrySet();
// Interface for entrySet elements
public interface Entry {
K getKey();
V getValue();
V setValue(V value);
}
}
Java平臺中包含了三種通用的Map實現:HashMap, TreeMap和LinkedHashMap。 此外,哈希表(Hashtable)也實現了Map接口。
Map接口基本操作
Map的基本操作(put, get, containsKey, containsValue, size, and isEmpty) 和哈希表非常相似。下面程序演示瞭如何從輸入字符串中創建單詞頻度表。
import java.util.*;
public class Freq {
public static void main(String[] args) {
Map<String, Integer> m = new HashMap<String, Integer>();
// Initialize frequency table from command line
for (String a : args) {
Integer freq = m.get(a);
m.put(a, (freq == null) ? 1 : freq + 1);
}
System.out.println(m.size() + " distinct words:");
System.out.println(m);
}
}
運行程序:
java Freq if it is to be it is up to me to delegate
輸出參數如下:
8 distinct words:
{to=3, delegate=1, be=1, it=2, up=1, if=1, me=1, is=2}
與Set和List接口類似,Map也加強了equals和hashCode函數,使得可以比較兩個Map對象是否包含相同的集合元素。
爲了轉換方便,所有的泛型Map實現都提供瞭如下形式的構造函數:
Map<K, V> copy = new HashMap<K, V>(m);
Map接口批量操作
Map接口批量操作主要爲clear和putAll兩個函數,這裏就不多介紹了。
Map的集合視圖方法使得Map可以以集合的形式展現其元素。Map的集合視圖有如下三種形式:
keySet — Map
中包含的鍵的數據集
values — Map
中包含的值的數據集
entrySet — Map
中包含的鍵值對的數據集
通過Map的集合視圖可以實現對Map中的元素遍歷,方式如下:
for (Map.Entry<KeyType, ValType> e : m.entrySet())
System.out.println(e.getKey() + ": " + e.getValue());
對象排序
Java平臺中提供了Comparable接口實現對象間的大小比較。Java平臺中實現了Comparable接口的常用類有:
Classes Implementing Comparable |
|
Class |
Natural Ordering |
Byte |
Signed numerical |
Character |
Unsigned numerical |
Long |
Signed numerical |
Integer |
Signed numerical |
Short |
Signed numerical |
Double |
Signed numerical |
Float |
Signed numerical |
BigInteger |
Signed numerical |
BigDecimal |
Signed numerical |
Boolean |
Boolean.FALSE < Boolean.TRUE |
File |
System-dependent lexicographic on path name |
String |
Lexicographic |
Date |
Chronological |
CollationKey |
Locale-specific lexicographic |
如果List的元素實現了Comparable接口,可以通過sort方法實現對List中的元素排序,使之順序排列。
如果List的元素沒有實現Comparable接口,調用sort函數則會ClassCastException拋出異常,因爲sort函數不知道如何比較List中的元素大小。
Comparable接口聲明如下:
public interface Comparable<T> {
public int compareTo(T o);
}
compareTo的返回值表示的意義如下:
<0:
表明源對象小於目標對象
=0
: 表明源對象等於目標對象
>0:
表明源對象大於目標對象
下列代碼實現了一個可以比較大小的人名對象:
import java.util.*;
public class Name implements Comparable<Name> {
private final String firstName, lastName;
public Name(String firstName, String lastName) {
if (firstName == null || lastName == null)
throw new NullPointerException();
this.firstName = firstName;
this.lastName = lastName;
}
public String firstName() { return firstName; }
public String lastName() { return lastName; }
public boolean equals(Object o) {
if (!(o instanceof Name))
return false;
Name n = (Name)o;
return n.firstName.equals(firstName) &&
n.lastName.equals(lastName);
}
public int hashCode() {
return 31*firstName.hashCode() + lastName.hashCode();
}
public String toString() {
return firstName + " " + lastName;
}
public int compareTo(Name n) {
int lastCmp = lastName.compareTo(n.lastName);
return (lastCmp != 0 ? lastCmp :
firstName.compareTo(n.firstName));
}
}
下列代碼演示了建立一個人名序列,並對其排序:
import java.util.*;
public class NameSort {
public static void main(String[] args) {
Name nameArray[] = {
new Name("John", "Lennon"),
new Name("Karl", "Marx"),
new Name("Groucho", "Marx"),
new Name("Oscar", "Grouch")
};
List<Name> names = Arrays.asList(nameArray);
Collections.sort(names);
System.out.println(names);
}
}
運行程序,輸出結果如下:
[Oscar Grouch, John Lennon, Groucho Marx, Karl Marx]
如果兩個對象沒有實現Comparable 接口,可以通過自比較器對象實現對象的大小比較。比較器對象是一個實現了Comparator接口的對象。Comparable接口聲明如下:
public interface Comparator<T> {
int compare(T o1, T o2);
}
該接口的compare函數接受兩個對象參數,通過返回值表示兩個對象的大小。
假定現在有一個如下所示的Employee類:
public class Employee implements Comparable<Employee> {
public Name name() { ... }
public int number() { ... }
public Date hireDate() { ... }
...
}
默認的排序方式是按名稱排序,但我們需要按僱傭日期實現對僱員信息重新排序,可以通過如下方式實現:
import java.util.*;
public class EmpSort {
static final Comparator<Employee> SENIORITY_ORDER =
new Comparator<Employee>() {
public int compare(Employee e1, Employee e2) {
return e2.hireDate().compareTo(e1.hireDate());
}
};
// Employee database
static final Collection<Employee> employees = ... ;
public static void main(String[] args) {
List<Employee>e = new ArrayList<Employee>(employees);
Collections.sort(e, SENIORITY_ORDER);
System.out.println(e);
}
}
SortedSet接口
SortedSet是一類特殊的Set,在SortedSet中的元素是按大小順序排列的。
SortedSet接口聲明如下:
public interface SortedSet<E> extends Set<E> {
// Range-view
SortedSet<E> subSet(E fromElement, E toElement);
SortedSet<E> headSet(E toElement);
SortedSet<E> tailSet(E fromElement);
// Endpoints
E first();
E last();
// Comparator access
Comparator<? super E> comparator();
}
SortedSet基本操作
SortedSet 繼承自Set,大多數操作是一致,SortedSet操作的特殊之處在於:
迭代器是按照元素大小遍歷
toArray
返回的數組是按照元素大小排序的
此外,儘管接口中沒有強制要求,Java平臺下的SortedSet實現的toString 函數返回的字符串中的元素也是順序打印的。
爲了轉換方便, 所有Collection實現都提供了一個標準的構造函數,使之能從另一個Collection初始化數據。SortedSet實現也不例外,除此之外,SortedSet構造函數一般還能加上一個比較器的參數,使之按照自定義比較算法排序。
SortedSet接口提供了first和last兩個函數來返回集合的起始和結尾的元素。如下所示:
Object predecessor = ss.headSet(o).last();
SortedMap接口
SortedMap是一類鍵按大小順序排列的特殊的Map。 接口定義如下:
public interface SortedMap<K, V> extends Map<K, V>{
Comparator<? super K> comparator();
SortedMap<K, V> subMap(K fromKey, K toKey);
SortedMap<K, V> headMap(K toKey);
SortedMap<K, V> tailMap(K fromKey);
K firstKey();
K lastKey();
}
SortedMap的特性和SortedSet類似,這裏就不多做接受了。
接口小結
集合接口interfaces使得集合操作獨立於其具體實現。Java集合框架繼承結構由兩顆接口樹構成:
第一棵樹的根節點爲Collection接口,它定義了所有集合的基本操作——如添加、刪除、遍歷等。它的子接口爲——Set, List和 Queue。它們提供了更加特殊的功能。
Set
接口不包含重複元素。它有一個子接口——SortedSet,SortedSet 中的元素是按大小順序排列的。
List
接口保存了元素的位置信息,可以通過位置索引來訪問List中的元素。
Queue
接口保證了元素的訪問順序(FIFO等)。
第二棵樹根節點爲Map接口,和哈希表類似,保持的是鍵值對的集合,可以通過鍵來實現對值元素的快速訪問。
Map
接口的子接口爲SortedMap,SortedMap中的鍵是按照大小順序排列的。
算法
Java平臺對List實例提供了一些通用的算法,能較高效高效的實現排序、亂序、查詢、極值等功能。
排序是使集合中的元素按一定大小順序排列的操作。
排序算法有兩種形式:按元素自然順序排序和自定義排序。
自然排序是按照元素的自然順序比較大小,如下所示:
import java.util.*;
public class Sort {
public static void main(String[] args) {
List<String> list = Arrays.asList(args);
Collections.sort(list);
System.out.println(list);
}
}
運行程序:
% java Sort i walk the line
輸出結果爲:
[i, line, the, walk]
The program was included only to show you that algorithms really are as easy to use as they appear to be.
自定義排序是通過自定義比較器來比較大小,如下所示:
// Make a List of all anagram groups above size threshold.
List<List<String>> winners = new ArrayList<List<String>>();
for (List<String> l : m.values())
if (l.size() >= minGroupSize)
winners.add(l);
// Sort anagram groups according to size
Collections.sort(winners, new Comparator<List<String>>() {
public int compare(List<String> o1, List<String> o2) {
return o2.size() - o1.size();
}});
// Print anagram groups.
for (List<String> l : winners)
System.out.println(l.size() + ": " + l);
亂序算法實現的功能和排序恰恰相反,它將集合中的元素打亂,使其隨機排列。在前面的集合接口的有關章節有過介紹,這裏就不累述了。
Collections類爲List提供了五中數據常規操作的算法,分別是:
- reverse — 使List中的元素按相反的順序排列
- fill — 將List的所有元素賦給一個特定值,通常用來初始化List。
- copy — 將源List中的元素拷貝到目標List中
- swap — 交換List中兩個元素的位置
- addAll — 將所有滿足特定條件的元素添加到一個集合中
可以通過binarySearch函數實現對一個有序的List進行折半查找,從而快速的查詢元素,如下所示:
int
pos = Collections.binarySearch(list, key);
if (pos < 0)
l.add(-pos-1);
Composition
Requency和disjoint算法可以用來測試集合的元素組成:
- frequency — 獲取某個元素在集合中的個數
- disjoint — 檢測兩個集合是否沒有共同的元素
獲取極值
可以通過min和 max 函數獲取集合中的極小值和極大值。