这里描述的多态算法是Java平台提供的可重用功能。它们全部来自 Collections
类,并且都采用静态方法的形式,其第一个参数是要对其执行操作的集合。Java平台提供的大多数算法都在List
实例上运行,但是其中一些算法 在任意 Collection
实例上运行。本节简要介绍以下算法:
- 排序
- 改组
- 例行数据处理
- 正在搜寻
- 组成
- 寻找极值
排序
排序算法对List
进行重新排序,以便其元素按照排序关系升序排列。提供了两种形式的操作。简单形式采用一个List
,并根据其元素的自然顺序对其进行排序。如果您不熟悉自然排序的概念,请阅读“对象排序”部分。sort
操作使用了快速优化且稳定的稍微优化的合并排序算法:
- 快速:它可以保证以
n log(n)
的时间运行,并且在几乎排序的列表上运行的速度要快得多。经验测试表明,它与高度优化的快速排序一样快。通常认为,快速排序比合并排序要快,但它不稳定且不能保证n log(n)
性能。 - 稳定:它不会重新排列相等的元素。如果您对不同属性重复对同一列表进行排序,这很重要。如果邮件程序的用户按邮寄日期对收件箱进行排序,然后按发件人对其进行排序,则用户自然希望来自给定发件人的当前连续邮件列表将(仍)按邮寄日期进行排序。仅当第二种情况稳定时,才能保证这一点。
以下 trivial program
按字典顺序(字母顺序)打印其参数。
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]
包含该程序只是为了向您展示算法确实像看起来一样容易使用。sort
的第二种形式除了List
之外还包含一个Comparator
,并使用Comparator
对元素进行排序。假设您要按照相反的大小打印先前示例中的字谜组——首先是最大的字谜组。下面的示例向您展示如何在sort
方法的第二种形式的帮助下实现这一目标。
回想一下,字谜组以List
实例的形式作为值存储在Map
中。修改后的打印代码将遍历Map
的值视图,将通过最小尺寸测试的每个List
放入List
中。然后,代码使用需要List
实例的Comparator
对该List
进行排序,并实现反向大小排序。最后,代码遍历已排序的List
,并打印其元素(字谜组)。以下代码替换了Anagrams
示例中main
方法末尾的打印代码。
// 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);
在与“Map接口”部分相同的词典上运行该程序,并使用最小的字谜组大小(八个)相同,将产生以下输出。
12: [apers, apres, asper, pares, parse, pears, prase,
presa, rapes, reaps, spare, spear]
11: [alerts, alters, artels, estral, laster, ratels,
salter, slater, staler, stelar, talers]
10: [least, setal, slate, stale, steal, stela, taels,
tales, teals, tesla]
9: [estrin, inerts, insert, inters, niters, nitres,
sinter, triens, trines]
9: [capers, crapes, escarp, pacers, parsec, recaps,
scrape, secpar, spacer]
9: [palest, palets, pastel, petals, plates, pleats,
septal, staple, tepals]
9: [anestri, antsier, nastier, ratines, retains, retinas,
retsina, stainer, stearin]
8: [lapse, leaps, pales, peals, pleas, salep, sepal, spale]
8: [aspers, parses, passer, prases, repass, spares,
sparse, spears]
8: [enters, nester, renest, rentes, resent, tenser,
ternes,��treens]
8: [arles, earls, lares, laser, lears, rales, reals, seral]
8: [earings, erasing, gainers, reagins, regains, reginas,
searing, seringa]
8: [peris, piers, pries, prise, ripes, speir, spier, spire]
8: [ates, east, eats, etas, sate, seat, seta, teas]
8: [carets, cartes, caster, caters, crates, reacts,
recast,��traces]
洗牌
shuffle
算法的作用与sort
相反,破坏了List
中可能存在的任何顺序痕迹。即,该算法基于来自随机性源的输入对List
进行重新排序,从而假定合理的随机性源,所有可能的排列均以相同的可能性发生。该算法在实施机会游戏中很有用。例如,它可以用于洗牌代表牌组的卡片列表对象。另外,它对于生成测试用例也很有用。
此操作有两种形式:一种采用List
并使用默认的随机源,另一种则要求调用者提供一个Random对象用作随机源。 此算法的代码在“List接口”部分中用作示例。
常规数据处理
Collections
类提供了五种用于对List
对象进行例行数据操作的算法,所有这些算法都非常简单:
reverse
—反转List
中元素的顺序。fill
— 用指定的值覆盖List
中的每个元素。此操作对于重新初始化List
很有用。copy
—接受两个参数,一个目标List
和一个源List
,然后将源的元素复制到目标中,覆盖其内容。目的List
必须至少与来源一样长。如果更长,则目标List
中的其余元素不受影响。swap
—交换List
中指定位置的元素。addAll
—将所有指定的元素添加到Collection
中。要添加的元素可以单独指定或作为数组指定。
搜寻
binarySearch
算法在排序列表中搜索指定的元素。该算法有两种形式。第一个带有一个List
和一个要搜索的元素(“搜索关键字”)。这种形式假定List
是根据其元素的自然顺序以升序排序的。第二种形式除List
和搜索键外还采用一个Comparator
,并假定List
根据指定的Comparator
以升序排序。排序算法可用于在调用binarySearch
之前对List
进行排序。
两种形式的返回值都相同。如果List
包含搜索关键字,则返回其索引。如果不是,则返回值是(-(insertion point) - 1)
,其中插入点是将值插入List
的点,第一个元素的索引大于该值的索引;或者list.size()
,如果List
中的所有元素都小于指定的值。这个丑陋的公式保证了只有当找到搜索键时,返回值才是>= 0
。将布尔值(found)
和整数(index)
组合成单个int
返回值基本上是一种技巧。
以下习惯用法可用于两种形式的binarySearch
操作,查找指定的搜索关键字,并将其插入适当的位置(如果尚不存在)。
int pos = Collections.binarySearch(list, key);
if (pos < 0)
l.add(-pos-1, key);
组成
频率和不相交算法测试一个或多个Collections
组成的某些方面:
frequency
—计算指定元素在指定集合中出现的次数disjoint
—确定两个Collections
是否不相交;也就是说,它们是否不包含共同点
寻找极值
min
和max
算法分别返回指定Collection
中包含的最小和最大元素。这两种操作都有两种形式。简单形式仅采用Collection
,并根据元素的自然顺序返回最小(或最大)元素。 第二种形式除了Collection
之外还采用Comparator
,并根据指定的Comparator
返回最小(或最大)元素。