Java容器中算法

1、算法

本部分介紹在容器體系中的一些常規算法:

​ 這些算法常常封裝到一些工具類中;l例如CollectionsArrays.

2、求最大值

//參數爲接口:所有實現給接口的類的對象都可以作爲參數傳遞進去
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
        Iterator<? extends T> i = coll.iterator();//獲取迭代器
        T candidate = i.next();//候選值

        while (i.hasNext()) {//獲取迭代器
            T next = i.next();//進行比較
            if (next.compareTo(candidate) > 0)
                candidate = next;
        }
        return candidate;
    }

3、排序與混排

Java程序設計語言:直接將所有元素轉入一個數組,對數組進行排序,然後,再將排序後的序列複製回列表

//排序方法1:元素已經實現了Comparable接口  
public static <T extends Comparable<? super T>> void sort(List<T> list) {
        Object[] a = list.toArray();//轉換爲數組
        Arrays.sort(a);//對數組進行排序
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }

//排序方法2:自定義比較器
public static <T> void sort(List<T> list, Comparator<? super T> c) {
        Object[] a = list.toArray();//轉換爲數組
        Arrays.sort(a, (Comparator)c);
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }


混排(shuffle)

如果提供的列表沒有實現RandomAccess接口,shuffle方法將元素複製到數組中,然後打亂數組元素的順序,最後將打亂順序後元素複製會列表、

 /**
     * Randomly permutes the specified list using a default source of
     * randomness.  All permutations occur with approximately equal
     * likelihood.
     *
     * <p>The hedge "approximately" is used in the foregoing description because
     * default source of randomness is only approximately an unbiased source
     * of independently chosen bits. If it were a perfect source of randomly
     * chosen bits, then the algorithm would choose permutations with perfect
     * uniformity.
     *
     * <p>This implementation traverses the list backwards, from the last
     * element up to the second, repeatedly swapping a randomly selected element
     * into the "current position".  Elements are randomly selected from the
     * portion of the list that runs from the first element to the current
     * position, inclusive.
     *
     * <p>This method runs in linear time.  If the specified list does not
     * implement the {@link RandomAccess} interface and is large, this
     * implementation dumps the specified list into an array before shuffling
     * it, and dumps the shuffled array back into the list.  This avoids the
     * quadratic behavior that would result from shuffling a "sequential
     * access" list in place.
     *
     * @param  list the list to be shuffled.
     * @throws UnsupportedOperationException if the specified list or
     *         its list-iterator does not support the <tt>set</tt> operation.
     */
    public static void shuffle(List<?> list) {
        Random rnd = r;
        if (rnd == null)
            r = rnd = new Random(); // harmless race.
        shuffle(list, rnd);
    }

    private static Random r;

    /**
     * Randomly permute the specified list using the specified source of
     * randomness.  All permutations occur with equal likelihood
     * assuming that the source of randomness is fair.<p>
     *
     * This implementation traverses the list backwards, from the last element
     * up to the second, repeatedly swapping a randomly selected element into
     * the "current position".  Elements are randomly selected from the
     * portion of the list that runs from the first element to the current
     * position, inclusive.<p>
     *
     * This method runs in linear time.  If the specified list does not
     * implement the {@link RandomAccess} interface and is large, this
     * implementation dumps the specified list into an array before shuffling
     * it, and dumps the shuffled array back into the list.  This avoids the
     * quadratic behavior that would result from shuffling a "sequential
     * access" list in place.
     *
     * @param  list the list to be shuffled.
     * @param  rnd the source of randomness to use to shuffle the list.
     * @throws UnsupportedOperationException if the specified list or its
     *         list-iterator does not support the <tt>set</tt> operation.
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static void shuffle(List<?> list, Random rnd) {
        int size = list.size();
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=size; i>1; i--)
                swap(list, i-1, rnd.nextInt(i));//交換
        } else {
            Object arr[] = list.toArray();

            // Shuffle array
            for (int i=size; i>1; i--)
                swap(arr, i-1, rnd.nextInt(i));

            // Dump array back into list
            // instead of using a raw type here, it's possible to capture
            // the wildcard but it will require a call to a supplementary
            // private method
            ListIterator it = list.listIterator();
            for (int i=0; i<arr.length; i++) {
                it.next();
                it.set(arr[i]);
            }
        }
    }

    /**
     * Swaps the elements at the specified positions in the specified list.
     * (If the specified positions are equal, invoking this method leaves
     * the list unchanged.)
     *
     * @param list The list in which to swap elements.
     * @param i the index of one element to be swapped.
     * @param j the index of the other element to be swapped.
     * @throws IndexOutOfBoundsException if either <tt>i</tt> or <tt>j</tt>
     *         is out of range (i &lt; 0 || i &gt;= list.size()
     *         || j &lt; 0 || j &gt;= list.size()).
     * @since 1.4
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static void swap(List<?> list, int i, int j) {
        // instead of using a raw type here, it's possible to capture
        // the wildcard but it will require a call to a supplementary
        // private method
        final List l = list;
        l.set(i, l.set(j, l.get(i)));
    }

    /**
     * Swaps the two specified elements in the specified array.
     */
    private static void swap(Object[] arr, int i, int j) {
        Object tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

4、二分查找

要想在數組中査找一個對象, 通常要依次訪問數組中的每個元素,直到找到匹配的元素
爲止。

然而, 如果數組是有序的, 就可以直接査看位於數組中間的元素, 看一看是否大於
要查找的元素。如果是, 用同樣的方法在數組的前半部分繼續查找; 否則, 用同樣的方法在
數組的後半部分繼續查找。這樣就可以將查找範圍縮減一半。一直用這種方式査找下去

  • Collections類的binarySearch方法實現了這個算法。
  • 注意,集合必須是排好序的,否則算法將返回錯誤的答案
  • 要想查找某個元素,必須提供集合(這個集合要實現List接口)
  • 如果集合沒有采用Comparable接口的compareTo方法進行排序,就還要提供一個比較器對象
  • 只有採用隨機訪問,二分查找纔有意義。如果,必須利用迭代方式一次次的遍歷鏈表的一半元素來找到中間位置的元素,二分查找就完全失去了優勢;因此,如果binarySearch算法提供一個鏈表,它將自動的變爲線性查找
public static <T>
    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
    //可以隨機訪問則進行二分查找:例如ArrayLIST
        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key);
        else
            //不可進行隨機訪問則實際上進行線性查找:例如LinkedList
            return Collections.iteratorBinarySearch(list, key);
    }

    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<? extends Comparable<? super 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
    }

5、簡單算法

static <T extends Comparab1e<? super T>> T min(Collection<T> elements )

static <T extends Comparable<? super T>> T max(Col 1ection<T> elements)
static <T> min( Col 1ection<T> elements, Comparator ? super T> c )
static <T> max( Col 1ection<T> elements, Comparator ? super T> c )
返回集合中最小的或最大的元素(爲清楚起見, 參數的邊界被簡化了)。

static <T> void copy(List<? super T> to, List<T> from)
將原列表中的所有元素複製到目辱列表的相應位1上。目標列表的長度至少與原列表一樣。

static <T> void fi11(List<? super T> 1, T value)
將列表中所有位置設置爲相同的值。

static <T> boolean addAl1(Collection<? super T> c, T. .. values )
將所有的值添加到集合中。 如果集合改變了, 則返回 tme。

static <T> boolean replaceAl 1(List<T> 1, T oldValue, T newValue)
用 newValue 取代所有值爲 oldValue 的元素。

static void swap(List<?> 1, int i, int j)
交換給定偏移量的兩個元素。

static void reverse(List<?> 1)
逆置列表中元素的順序。例如, 逆置列表 [,t a, r] 後將得到列表 [r, a, t。] 這個方法的時間複雜度爲 O (n,) ri 爲列表的長度。

6、批操作

很多操作會"成批"複製或刪除元素

通過使用一個子範圍視圖,可以把批操作限制在子列表和子集上。

  1. Coll1.removeAll(coll2) 將從coll1中刪除coll2中出現的所有元素
  2. coll1.retainAll(coll2) 會從coll1中刪除coll2中出現額元素
  3. coll1.addAll(coll2)

addAll方法實現

public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);//檢測索引
        boolean modified = false;
        for (E e : c) {  //遍歷
            add(index++, e);
            modified = true;
        }
        return modified;
    }

removeAll方法實現

 public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        boolean modified = false;
        Iterator<?> it = iterator();//遍歷
        while (it.hasNext()) {
            if (c.contains(it.next())) {//如果包含
                it.remove(); //刪除
                modified = true;
            }
        }
        return modified;
    }

7、編寫自己的算法

如果編寫自己的算法(實際上,是以集合作爲參數的任何方法,) 應該儘可能地使用接口

發佈了155 篇原創文章 · 獲贊 18 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章