1、算法
本部分介紹在
容器體系中
的一些常規算法: 這些算法常常封裝到一些
工具類中
;l例如Collections
,Arrays
.
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 < 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;
}
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、批操作
很多操作會"成批"複製或刪除元素
通過使用一個子範圍視圖,可以把批操作限制在子列表和子集上。
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;
}
7、編寫自己的算法
如果編寫自己的算法(實際上,是以集合作爲參數的任何方法,) 應該儘可能地使用接口