比较函数
TreeSet和TreeMap都按排序顺序存储元素。然而,精确定义采用何种“排序顺序”的是比较函数。通常在默认的情况下,这些类通过使用被Java称之为“自然顺序”的顺序存储它们的元素,而这种顺序通常也是你所需要的(A在B的前面,1在2的前面,等等)。如果需要用不同的方法对元素进行排序,可以在构造集合或映射时,指定一个Comparator对象。这样做为你提供了一种精确控制如何将元素储存到排序类集和映射中的能力。

Comparator接口定义了两个方法:compare( )和equals( )。这里给出的compare( )方法按顺序比较了两个元素:

int compare(Object obj1, Object obj2)

obj1和obj2是被比较的两个对象。当两个对象相等时,该方法返回0;当obj1大于obj2时,返回一个正值;否则,返回一个负值。如果用于比较的对象的类型不兼容的话,该方法引发一个ClassCastException异常。通过覆盖compare( ),可以改变对象排序的方式。例如,通过创建一个颠倒比较输出的比较函数,可以实现按逆向排序。

这里给出的equals( )方法,测试一个对象是否与调用比较函数相等:

boolean equals(Object obj)

obj是被用来进行相等测试的对象。如果obj和调用对象都是Comparator的对象并且使用相同的排序。该方法返回true.否则返回false.重载equals( )方法是没有必要的,大多数简单的比较函数都不这样做。

1 使用比较函数

下面是一个说明定制的比较函数能力的例子。该例子实现compare( )方法以便它按正常顺序的逆向进行操作。因此,它使得一个树集合按逆向的顺序进行存储。

// Use a custom comparator.
import java.util.Comparator;
//A reverse comparator for strings.
public class MyComp implements Comparator {
    public int compare(Object a, Object b) {
        String aStr, bStr;
        aStr = (String) a;
        bStr = (String) b;
        // reverse the comparison
        return bStr.compareTo(aStr);
    }

    // no need to override equals
}

import java.util.Iterator;
import java.util.TreeSet;

public class CompDemo {
    public static void main(String[] args) {
        // Create a tree set
        TreeSet ts = new TreeSet(new MyComp());
        // Add elements to the tree set
        ts.add(“C”);
        ts.add(“A”);
        ts.add(“B”);
        ts.add(“E”);
        ts.add(“F”);
        ts.add(“D”);
        // Get an iterator
        Iterator i = ts.iterator();
        // Display elements
        while (i.hasNext()) {
            Object element = i.next();
            System.out.print(element + ” “);
        }

        System.out.println();
    }

}

正如下面的输出所示,树按照逆向顺序进行存储:

F E D C B A

仔细观察实现Comparator并覆盖compare( )方法的MyComp类(正如前面所解释的那样,覆盖equals( )方法既不是必须的,也不是常用的)。在compare( )方法内部,String方法compareTo( )比较两个字符串。然而由bStr??不是aStr??调用compareTo( )方法,这导致比较的结果被逆向。

对应一个更实际的例子,下面的例子是用TreeMap程序实现前面介绍的存储账目资产平衡表例子的程序。在前面介绍的程序中,账目是按名进行排序的,但程序是以按照名字进行排序开始的。下面的程序按姓对账目进行排序。为了实现这种功能,程序使用了比较函数来比较每一个账目下姓的排序。得到的映射是按姓进行排序的。

//Use a comparator to sort accounts by last name.
import java.util.Comparator;

//Compare last whole words in two strings.
public class TComp implements Comparator {

    public int compare(Object a, Object b) {
        int i, j, k;
        String aStr, bStr;
        aStr = (String) a;
        bStr = (String) b;
        // find index of beginning of last name
        i = aStr.lastIndexOf(‘ ‘);
        j = bStr.lastIndexOf(‘ ‘);
        k = aStr.substring(i).compareTo(bStr.substring(j));
        if (k == 0) // last names match, check entire name
            return aStr.compareTo(bStr);
        else
            return k;
    }

    // no need to override equals
}

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class TreeMapDemo2 {
    public static void main(String[] args) {
        // Create a tree map
        TreeMap tm = new TreeMap(new TComp());
        // Put elements to the map
        tm.put(“John Doe”, new Double(3434.34));
        tm.put(“Tom Smith”, new Double(123.22));
        tm.put(“Jane Baker”, new Double(1378.00));
        tm.put(“Todd Hall”, new Double(99.22));
        tm.put(“Ralph Smith”, new Double(-19.08));
        // Get a set of the entries
        Set set = tm.entrySet();
        // Get an iterator
        Iterator itr = set.iterator();
        // Display elements
        while (itr.hasNext()) {
            Map.Entry me = (Map.Entry) itr.next();
            System.out.print(me.getKey() + “: “);
            System.out.println(me.getValue());
        }

        System.out.println();
        // Deposit 1000 into John Doe’s account
        double balance = ((Double) tm.get(“John Doe”)).doubleValue();
        tm.put(“John Doe”, new Double(balance + 1000));
        System.out.println(“John Doe’s new balance: ” + tm.get(“John Doe”));
    }

}


这里是程序的输出结果,注意此时的账目是按姓进行排序的:

Jane Baker: 1378.0

John Doe: 3434.34

Todd Hall: 99.22

Ralph Smith: -19.08

Tom Smith: 123.22

John Doe’s new balance: 4434.34

比较函数类TComp比较两个包含姓和名的字符串。它首先比较姓。具体是这样做的,它首先寻找每一个字符串中最后一个空格的下标,然后比较从这个位置开始的每一个元素的子字符串。当两个字符串中姓完全相等时,它再比较两个名。这样就形成了一个先按姓进行排序,在姓相同的情况下,再按名字进行排序的树型映射。通过程序的输出中RalphSmith出现在Tom Smith之前的结果可以看到这一点。

Reference:

http://www.blogjava.net/yesjoy/articles/126046.html

Advertisements