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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章