java 1.2添加了自己的一套实用工具,可用来对数组或列表进行排列和搜索。这些工具都属于两个新类的“静态”方法。这两个类分别是用于排序和搜索数组的arrays,以及用于排序和搜索列表的collections。
1. 数组
arrays类为所有基本数据类型的数组提供了一个过载的sort()和binarysearch(),它们亦可用于string和object。下面这个例子显示出如何排序和搜索一个字节数组(其他所有基本数据类型都是类似的)以及一个string数组:
//: array1.java
// testing the sorting & searching in arrays
package c08.newcollections;
import java.util.*;
public class array1 {
static random r = new random();
static string ssource =
"abcdefghijklmnopqrstuvwxyz" +
"abcdefghijklmnopqrstuvwxyz";
static char[] src = ssource.tochararray();
// create a random string
public static string randstring(int length) {
char[] buf = new char[length];
int rnd;
for(int i = 0; i < length; i++) {
rnd = math.abs(r.nextint()) % src.length;
buf[i] = src[rnd];
}
return new string(buf);
}
// create a random array of strings:
public static
string[] randstrings(int length, int size) {
string[] s = new string[size];
for(int i = 0; i < size; i++)
s[i] = randstring(length);
return s;
}
public static void print(byte[] b) {
for(int i = 0; i < b.length; i++)
system.out.print(b[i] + " ");
system.out.println();
}
public static void print(string[] s) {
for(int i = 0; i < s.length; i++)
system.out.print(s[i] + " ");
system.out.println();
}
public static void main(string[] args) {
byte[] b = new byte[15];
r.nextbytes(b); // fill with random bytes
print(b);
arrays.sort(b);
print(b);
int loc = arrays.binarysearch(b, b[10]);
system.out.println("location of " + b[10] +
" = " + loc);
// test string sort & search:
string[] s = randstrings(4, 10);
print(s);
arrays.sort(s);
print(s);
loc = arrays.binarysearch(s, s[4]);
system.out.println("location of " + s[4] +
" = " + loc);
}
} ///:~
类的第一部分包含了用于产生随机字串对象的实用工具,可供选择的随机字母保存在一个字符数组中。randstring()返回一个任意长度的字串;而readstrings()创建随机字串的一个数组,同时给定每个字串的长度以及希望的数组大小。两个print()方法简化了对示范数组的显示。在main()中,random.nextbytes()用随机选择的字节填充数组自变量(没有对应的random方法用于创建其他基本数据类型的数组)。获得一个数组后,便可发现为了执行sort()或者binarysearch(),只需发出一次方法调用即可。与binarysearch()有关的还有一个重要的警告:若在执行一次binarysearch()之前不调用sort(),便会发生不可预测的行为,其中甚至包括无限循环。
对string的排序以及搜索是相似的,但在运行程序的时候,我们会注意到一个有趣的现象:排序遵守的是字典顺序,亦即大写字母在字符集中位于小写字母的前面。因此,所有大写字母都位于列表的最前面,后面再跟上小写字母――z居然位于a的前面。似乎连电话簿也是这样排序的。
2. 可比较与比较器
但假若我们不满足这一排序方式,又该如何处理呢?例如本书后面的索引,如果必须对以a或a开头的词条分别到两处地方查看,那么肯定会使读者颇不耐烦。
若想对一个object数组进行排序,那么必须解决一个问题。根据什么来判定两个object的顺序呢?不幸的是,最初的java设计者并不认为这是一个重要的问题,否则就已经在根类object里定义它了。这样造成的一个后果便是:必须从外部进行object的排序,而且新的集合库提供了实现这一操作的标准方式(最理想的是在object里定义它)。
针对object数组(以及string,它当然属于object的一种),可使用一个sort(),并令其接纳另一个参数:实现了comparator接口(即“比较器”接口,新集合库的一部分)的一个对象,并用它的单个compare()方法进行比较。这个方法将两个准备比较的对象作为自己的参数使用――若第一个参数小于第二个,返回一个负整数;若相等,返回零;若第一个参数大于第二个,则返回正整数。基于这一规则,上述例子的string部分便可重新写过,令其进行真正按字母顺序的排序:
//: alphacomp.java
// using comparator to perform an alphabetic sort
package c08.newcollections;
import java.util.*;
public class alphacomp implements comparator {
public int compare(object o1, object o2) {
// assume it's used only for strings...
string s1 = ((string)o1).tolowercase();
string s2 = ((string)o2).tolowercase();
return s1.compareto(s2);
}
public static void main(string[] args) {
string[] s = array1.randstrings(4, 10);
array1.print(s);
alphacomp ac = new alphacomp();
arrays.sort(s, ac);
array1.print(s);
// must use the comparator to search, also:
int loc = arrays.binarysearch(s, s[3], ac);
system.out.println("location of " + s[3] +
" = " + loc);
}
} ///:~
通过造型为string,compare()方法会进行“暗示”性的测试,保证自己操作的只能是string对象――运行期系统会捕获任何差错。将两个字串都强迫换成小写形式后,string.compareto()方法会产生预期的结果。
若用自己的comparator来进行一次sort(),那么在使用binarysearch()时必须使用那个相同的comparator。
arrays类提供了另一个sort()方法,它会采用单个自变量:一个object数组,但没有comparator。这个sort()方法也必须用同样的方式来比较两个object。通过实现comparable接口,它采用了赋予一个类的“自然比较方法”。这个接口含有单独一个方法――compareto(),能分别根据它小于、等于或者大于自变量而返回负数、零或者正数,从而实现对象的比较。下面这个例子简单地阐示了这一点:
//: compclass.java
// a class that implements comparable
package c08.newcollections;
import java.util.*;
public class compclass implements comparable {
private int i;
public compclass(int ii) { i = ii; }
public int compareto(object o) {
// implicitly tests for correct type:
int argi = ((compclass)o).i;
if(i == argi) return 0;
if(i < argi) return -1;
return 1;
}
public static void print(object[] a) {
for(int i = 0; i < a.length; i++)
system.out.print(a[i] + " ");
system.out.println();
}
public string tostring() { return i + ""; }
public static void main(string[] args) {
compclass[] a = new compclass[20];
for(int i = 0; i < a.length; i++)
a[i] = new compclass(
(int)(math.random() *100));
print(a);
arrays.sort(a);
print(a);
int loc = arrays.binarysearch(a, a[3]);
system.out.println("location of " + a[3] +
" = " + loc);
}
} ///:~
当然,我们的compareto()方法亦可根据实际情况增大复杂程度。
3. 列表
可用与数组相同的形式排序和搜索一个列表(list)。用于排序和搜索列表的静态方法包含在类collections中,但它们拥有与arrays中差不多的签名:sort(list)用于对一个实现了comparable的对象列表进行排序;binarysearch(list,object)用于查找列表中的某个对象;sort(list,comparator)利用一个“比较器”对一个列表进行排序;而binarysearch(list,object,comparator)则用于查找那个列表中的一个对象(注释⑨)。下面这个例子利用了预先定义好的compclass和alphacomp来示范collections中的各种排序工具:
//: listsort.java
// sorting and searching lists with 'collections'
package c08.newcollections;
import java.util.*;
public class listsort {
public static void main(string[] args) {
final int sz = 20;
// using "natural comparison method":
list a = new arraylist();
for(int i = 0; i < sz; i++)
a.a
闽公网安备 35060202000074号