同種のデータの集まりがあるとき、それをソート(整順)させたいという事は 多いものと思います。アルゴリズムの本には必ずといってよいほど色々な ソートに関して記述されています。 ただJavaでプログラムを作成する場合、自分で何かソートのアルゴリズムを実装 する、というような事はしません(何か特別な理由がある場合は別ですが)。 配列をソートしたいときはjava.util.Arrays、Collectionをソートしたいときは、 java.util.Collectionsのクラスメソッドを使うのが普通です。 例えばStringの配列を昇順にソートしたいのであれば、
String[] stringArray = getArrayFromAnywhere(); java.util.Arrays.sort(stringArray);とするだけです。int[]やchar[]といった配列でも同じようにソートできます。 これらのメソッドはQuick Sortと呼ばれるアルゴリズムが使われています。
では自分で作ったクラスのインスタンスをソートするには、 どうすればよいでしょうか。2つの方法があります。1つはソートしたい オブジェクトのクラスで、java.lang.Comparableインタフェースを implementsする方法、もう一つはソート対象のオブジェクトとは別に java.util.Comparatorをimplementsしたクラスを作成する方法です。
/** * 名前と年齢のクラス。 */ public class Person { /** 名前 */ public String name; /** 年齢 >= 0 */ public int age; }このクラスのインスタンスを年齢順にソートしたい場合、Personで java.lang.Comparableインタフェースをimplementsします。 ComparableインタフェースにはcompareTo()というメソッドがありますので、 これを実装します。compareToの引数は比較対象のObjectで、 自分自身と同じクラス(上記の場合はPerson)のインスタンスであることを 仮定して構いません。 compareTo()の戻り値は、自分の方が小さいときは負の値、同じなら0、 自分の方が大きいなら正の値を返すことになっています。したがってこの場合は、
/** * 名前と年齢のクラス。 */ public class Person implements Comparable { /** 名前 */ public String name; /** 年齢 >= 0 */ public int age; /** 比較メソッド。ageの昇順にソートしたい。 * @param object 比較対象のPersonオブジェクト */ public int compareTo(Object object) { Person operand = (Person) object; if (this.age < operand.age) { return -1; } else if (this.age > operand.age) { return 1; } else { return 0; } } }という感じです。
return this.age - operand.age;とする手も ありますが、この場合は年齢だから問題になりませんが、整数同士の引き算は オーバーフローを発生させる可能性がありますので、 面倒でもifで評価したほうが安全でしょう。
Comparableをimplementsしていれば、
Person[] personArray = getPersonArrayFromAnywhere(); java.util.Arrays.sort(personArray);という風にjava.util.Arrays.sort()を使うことが出来ます。逆順にソート したい場合は、compareTo()メソッドで返す値を正負逆にすれば良いわけです。 String等のクラスもComparableがimplementsされています。
Comparableがimplementsされているクラスのオブジェクトであれば、その Collection、例えばListをソートすることも容易です。
List personList = getPersonList() // Personオブジェクトのリスト Collections.sort(personList);とすれば、personListがソートされます。
自分で作成しているクラスならComparableをimplementsすれば良いのですが、 自分では内部をさわることが出来ないクラスの場合は困ります。ラッピング するようなクラスを作ってしまうことも出来ますが、ソートをするだけなら java.util.Comparatorをimplementsするクラスを別に用意したほうが簡単です。
例えばStringの配列を逆順にソートする場合を考えましょう。Stringは Comparableをimplementsしていますが、これは昇順ソートを前提にしています。 しかもStringはfinalクラスですので継承してクラスを作ることが出来ません。 Stringを含むクラスを作るのも何だし、という場合にComparatorの登場と なります。
java.util.Comparatorインタフェースはcompare()とequals()という二つの メソッドを定義することになっていますが、equals()は、Comparator自身の 等値性の話なので、ソートには直接は関係しません。必要なのはcompare() メソッドの方です。これはComparableのcompareTo()と似ていて、2つの引数 のうち、1つ目の引数が小さければ負の値、同じならば0、大きければ正の値を 返すように実装します。逆順ソートの場合は正負を反対にします。 Stringの逆順ソートを行う場合は、
public class ReverseComparator implements java.util.Comparator { public int compare(Object object1, Object object2) { String string1 = (String) object1; String string2 = (String) object2; return (string1.compareTo(string2)) * (-1); } }という風にComparatorの実装を作成します。すると、
String[] stringArray = getStringArrayFromAnywhere(); Arrays.sort(stringArray, new ReverseComparator());と、sort()に配列とともにReverseComparatorのインスタンスを渡すことで、 逆順ソートが実現できます。
Collectionの場合もComparatorを渡すことが出来ます。上記の文字列の逆順 ソートの場合、
List stringList = getStringListFromAnywhere(); Collections.sort(stringList, new ReverseComparator());で出来ます。まじめにソートのアルゴリズムについて勉強しておく事は 重要ですが、実装にあたってはあるものを利用するという考えも重要です。 そういう場合はjava.util.Arraysやjava.util.Collectionsといった ユーティリティクラスが便利です。