本部分介绍在
容器体系中
的一些常规算法: 这些算法常常封装到一些
工具类中
;l例如Collections
,Arrays
.
//参数为接口:所有实现给接口的类的对象都可以作为参数传递进去
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;
}
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]);
}
}
如果提供的列表没有实现
RandomAccess
接口,shuffle
方法将元素复制到数组中,然后打乱数组元素的顺序,最后将打乱顺序后元素复制会列表、
/**
* Randomly permutes the specified list using a default source of
* randomness. All permutations occur with approximately equal
* likelihood.
*
* 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.
*
*
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.
*
*
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 set 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.
*
* 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.
*
* 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 set 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 i or j
* is out of range (i < 0 || i >= list.size()
* || j < 0 || j >= 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;
}
要想在数组中査找一个对象, 通常要依次访问数组中的每个元素,直到找到匹配的元素
为止。然而, 如果数组是有序的, 就可以直接査看位于数组中间的元素, 看一看是否大于
要查找的元素。如果是, 用同样的方法在数组的前半部分继续查找; 否则, 用同样的方法在
数组的后半部分继续查找。这样就可以将查找范围缩减一半。一直用这种方式査找下去
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
}
static
• static
•static
• static
返回集合中最小的或最大的元素(为清楚起见, 参数的边界被简化了)。
•static
将原列表中的所有元素复制到目辱列表的相应位1上。目标列表的长度至少与原列表一样。
•static
将列表中所有位置设置为相同的值。
•static
将所有的值添加到集合中。 如果集合改变了, 则返回 tme。
•static
用 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 为列表的长度。
很多操作会"成批"复制或删除元素
通过使用一个子范围视图,可以把批操作限制在子列表和子集上。
Coll1.removeAll(coll2)
将从coll1中删除coll2中出现的所有元素coll1.retainAll(coll2)
会从coll1中删除coll2中出现额元素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;
}
如果编写自己的算法(实际上,是以集合作为参数的任何方法,) 应该尽可能地使用接口