Java集合概述

集合概述

集合(collection)——有時也被稱作容器, 用來把具有相同性質的一類東西,匯聚成一個整體。Collections被廣泛應用於存儲,獲取及操作數據。

集合框架

集合框架(Collections Framework)是對進行collections表示和操作的統一架構,Java 集合框架包括如下幾個部分:

  1. 接口: 表示集合的抽象數據類型。接口提供了讓我們對集合中所表示的內容進行單獨操作的可能。在面嚮對象語言中,接口通常以繼承的形式表示。
  2. 實現: 也就是集合框架中接口的具體實現。實際它們就是那些可複用的數據結構。
  3. 算法: 在一個實現了某個集合框架中的接口的對象身上完成某種有用的計算的方法,例如查找、排序等。這些算法通常是多態的,因爲相同的方法可以在同一個接口被多個類實現時有不同的表現。

Java集合框架的益處

使用Java 集合框架將給我們帶來如下好處:

  1. 減少了程序設計的辛勞。集合框架通過提供有用的數據結構和算法使你能集中注意力於你的程序的重要部分上,而不是爲了讓程序能正常運轉而將注意力於低層設計上。通過這些在無關API之間的簡易的互用性,使你免除了爲改編對象或轉換代碼以便聯合這些API而去寫大量的代碼。
  2. 提高了程序速度和質量。集合框架通過提供對有用的數據結構和算法的高性能和高質量的實現使 你的程序速度和質量得到提高。因爲每個接口的實現是可互換的,所以你的程序可以很容易的通過改變一個實現而進行調整。另外,你將可以從寫你自己的數據結構 的苦差事中解脫出來,從而有更多時間關注於程序其它部分的質量和性能。
  3. 減少去學習和使用新的API 的辛勞。許多API天生的有對集合的存儲和獲取。在過去,這樣的API都有一些子API幫助操縱它的集合內容,因此在那些特殊的子API之間就會缺乏一致性,你也不得不從零開始學習,並且在使用時也很容易犯錯。而標準集合框架接口的出現使這個問題迎刃而解。
  4. 減少了設計新API的努力。設計者和實現者不用再在每次創建一種依賴於集合內容的API時重新設計,他們只要使用標準集合框架的接口即可。
  5. 集合框架鼓勵軟件的複用。對於遵照標準集合框架接口的新的數據結構天生即是可複用的。同樣對於操作一個實現了這些接口的對象的算法也是如此。

接口

集合核心接口(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);

}

通過這些操作函數,我們可以進行獲取集合中元素的個數 (sizeisEmpty),判斷集合中是否包含某個元素(contains),在集合中增加或刪除元素(addremove),獲取訪問迭代器(iterator)等操作。

遍歷Collection

有兩種方式可以實現對集合的遍歷:

  • 使用 for-each 循環
  • 使用 Iterators.

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 — 刪除集合中所有元素

addAllremoveAll retainAll 操作中,如果集合的元素被更改,則返回true

下列代碼演示瞭如何從一個集合中移除所有包含特定值的元素:

c.removeAll(Collections.singleton(e));

另外一個常用的批量操作是移除集合中所有的null元素:

c.removeAll(Collections.singleton(null));

Collection和數組間的轉換

數組轉化爲集合:

List<String> c = new ArrayList<String>(…);

集合轉化爲數組:

Object[] a = c.toArray();

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的批量操作和離散數學的集合操作的概論結合的非常好,假如s1s2是兩個Set,它們間的批量操作如下:

  • s1.containsAll(s2) — 判斷s2是否是s1的子集
  • s1.addAll(s2) — s1轉化爲s1s2的並集
  • s1.retainAll(s2) —s1轉化爲s1s2的交集
  • s1.removeAll(s2) —s1轉化爲s1s2的差集

我們來繼續看一下前面的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的實現:ArrayListLinkedList

Vector的比較

ListVector有許多相似之處。ListVector的一些常用的Api進行了改進,使之更加簡單易用。

對於如下元素賦值操作:

a[i] = a[j].times(a[k]);

Vectorv.setElementAt(v.elementAt(j).times(v.elementAt(k)), i);

Listv.set(i, v.get(j).times(v.get(k)));

可以看到,List的元素的獲取和設置操作比Vector的更加簡潔。

此外,Listadd(int, E)對應與VectorinsertElementAt(Object, int)操作,用subList操作統一代替了VectorindexOf, lastIndexOfsetSize三個操作。

List接口基本操作

List接口實現了所有Collection接口定義的功能,這裏就不再累述。

另外,可以通過addAllinserts進行元素的批量插入操作。

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),並且實現同樣的功能。hasPreviousprevious函數使用方式和hasNextnext類似,通過它們組合使用可以實現向前迭代,方式如下:

for (ListIterator<Type> it = list.listIterator(list.size());

     it.hasPrevious(); ) {

    Type t = it.previous();

    ...

}

注意listIterator的構造方式,List提供兩個函數用來構造listIteratorlistIterator()函數返回list起始位置的迭代器,listIterator(index)函數返回list某個位置的迭代器,若某個list的長度爲n,則index的取值範圍爲0n,如下圖所示:

圖表 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) 返回失敗碼 (通常是nullfalse)。下表顯示了常用操作的失敗處理方式:

Queue Interface Structure

 

Throws exception

Returns special value

Insert

add(e)

offer(e)

Remove

remove()

poll()

Examine

element()

peek()

bounded是一種可以限制元素的數目Queuejava.util.concurrent中定義了一些bounded的實現,java.util中的Queue的實現都不是bounded

Queue中插入元素可以通過add函數(繼承自Collection)和inserts函數進行,它們的區別是出錯時的處理方式不同。

訪問Queue中的元素可以通過remove函數(繼承自Collection)和poll函數進行,它們的區別是出錯時的處理方式不同。

此外,也可以通過element函數(繼承自Collection)和peek函數訪問Queue中的元素,它們的區別是出錯時的處理方式不同。與removepoll函數不同的是,它們訪問Queue後並不刪除Queue的元素。

Queue 實現通常通常不允許插入null元素,但LinkedList(實現了Queue接口)卻是個例外(由於某些歷史原因)。但在使用過程中,應儘量避免將null插入到其中,因爲它也是元素訪問函數pollpeek執行失敗的返回值。

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實現:HashMapTreeMapLinkedHashMap。 此外,哈希表(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}

SetList接口類似,Map也加強了equalshashCode函數,使得可以比較兩個Map對象是否包含相同的集合元素。

爲了轉換方便,所有的泛型Map實現都提供瞭如下形式的構造函數:

Map<K, V> copy = new HashMap<K, V>(m);

Map接口批量操作

Map接口批量操作主要爲clearputAll兩個函數,這裏就不多介紹了。

集合視圖

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接口提供了firstlast兩個函數來返回集合的起始和結尾的元素。如下所示:

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接口不包含重複元素。它有一個子接口——SortedSetSortedSet 中的元素是按大小順序排列的。
  • List接口保存了元素的位置信息,可以通過位置索引來訪問List中的元素。
  • Queue接口保證了元素的訪問順序(FIFO等)。
  • 第二棵樹根節點爲Map接口,和哈希表類似,保持的是鍵值對的集合,可以通過鍵來實現對值元素的快速訪問。
  • Map接口的子接口爲SortedMapSortedMap中的鍵是按照大小順序排列的。

算法

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提供了五中數據常規操作的算法,分別是:

  1. reverse — 使List中的元素按相反的順序排列
  2. fill — 將List的所有元素賦給一個特定值,通常用來初始化List。
  3. copy — 將源List中的元素拷貝到目標List中
  4. swap — 交換List中兩個元素的位置
  5. addAll — 將所有滿足特定條件的元素添加到一個集合中

查詢

可以通過binarySearch函數實現對一個有序的List進行折半查找,從而快速的查詢元素,如下所示:

int pos = Collections.binarySearch(list, key);
if (pos < 0)
    l.add(-pos-1);

Composition

Requency和disjoint算法可以用來測試集合的元素組成:

  1. frequency — 獲取某個元素在集合中的個數
  2. disjoint — 檢測兩個集合是否沒有共同的元素

獲取極值

可以通過min和 max 函數獲取集合中的極小值和極大值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章