我们假定关注的主要对象是重新排列数组元素的算法,其中每个元素都有一个主键。排序算法的主要目标就是将所有元素的主键按照某种方式排列(通常是按大小或是字母顺序)。排序后索引圈套的主键大于等于索引较小的主键。元素和主键的具体性质在不同的应用中千差万别。在Java中,元素通常都是对象,对主键的抽象描述则是通过一种内置的机制(Comparable接口)来完成的。
排序算法类的模板:
public class Example
{
public static void sort(Comparable[] a)
{ /*不同的排序算法名字不同*/ }
private static boolean less(Comparable v, Comparable w)
{ // 对元素进行比较
return v.compareTo(w) < 0;
}
private static void exch(Comparable[] a, int i, int j)
{ // 将元素交换位置
Comparable t = a[i]; a[i] = a[j]; a[j] = t;
}
private static void show(Comparable[] a)
{ // 在单行中打印数组
for(int i = 0; i < a.length; ++i)
stdOut.print(a[i] + " ");
stdOut.println();
}
public static boolean isSorted(Comparable[] a)
{ //测试数组元素是否有序
for(int i =1; i < a.length; ++i)
if(less(a[i], a[i-1])) return false;
return true;
}
public static void main(String[] args)
{ // 从标准输入读取字符串,将它们排序并输出
String[] a = In.readStrings();
sort(a);
assert isSorted(a);
show(a);
}
}
验证:为了谨慎起见,我们会在测试代码中添加一条语句assert isSorted(a);来确认排序后数组元素都是有序的。
运行时间:首先,要计算各个排序算法在不同一随机输入下的基本操作的次数(包括比较和交换,或者是读写数组的次数)。然后,我们用这些数据来估计算法的相对性能并介绍在实验中验证这些猜想所使用的工具。在研究排序算法时,我们需要计算比较和交换的数量。对于不交换元素的算法,我们会计算访问数组的次数。
额外的内存使用:排序算法的额外内存开销和运行时间是同等重要的。排序算法可以分为两类:除了函数调用所需的栈和固定数目的实例变量之外无需额外内存的原地排序算法,以及需要额外内存空间来存储另一份数组副本的其他排序算法。
数据类型:遵守Java惯例的好处是很多我们希望排序的数据都实现了Comparable接口。例如,Java中封闭数字的类型Integer和Double,以及String和其他许多高级数据类型(如File和URL)都实现了Comparable接口。因此我们可以直接用这些类型的数组作为参数调用排序方法。在创建自己的数据类型时,我们只要实现Comparable接口就能够保证Example可以将其排序。要做到这一点,只需要实现一个comparaTo()方法来定义目标类型对象的自然次序。如以下的代码所示:
public class Date implements Comparable<Date>
{
private final int day;
private final int month;
private final int year;
public Date(int d, int m, int y)
{ day = d; month = m; year = y; }
public int day(){return day;}
public int month(){return month;}
public int year(){return year;}
public int comparaTo(Date that)
{
if(this.year > that.year) return +1;
if(this.year < that.year) return -1;
if(this.month > that.month) return +1;
if(this.month < that.month) return -1;
if(this.day > that.day) return +1;
if(this.day < that.day) return -1;
return 0;
}
public String toString()
{ return month + "/" + day + "/" + year; }
}
compareTo()实现了Comparable接口的任意数据类型的对象的大小顺序的定义。需要注意的是compareTo()方法不一定会乃至进行比较的实例的所有实例变量,毕竟数组元素的主键很可能只是每个元素的一小部分。