web-dev-qa-db-ja.com

SortedSet / SortedMapをJava後方に反復する最良の方法

SortedMapのエントリセット(SortedSet)を逆方向に繰り返す必要があります。私が書いているコードは、1秒間に数千回、場合によってはそれ以上、多くの場所から呼び出されるため、パフォーマンスに非常に敏感です。それを最速の方法で行うためのアドバイスはありますか?

20

Java 1.6では NavigableSet を使用できます。

25
starblue

マップに入力する前にこれを使用してください:

SortedMap sortedMap = new TreeMap(Java.util.Collections.reverseOrder());
22
user1653195

コレクションを反復処理するより速い方法は、コレクションの配列コピーを取得することです。これは、オブジェクトやメソッド呼び出しを作成せずに、前後に繰り返すことができます。欠点は、コレクションが変更されるたびに、コレクションだけでなくコレクションも更新する必要があることです。

次の例では、1000個を超える要素を順方向または逆方向に反復するのに平均1,208nsかかります。

import Java.util.Comparator;
import Java.util.Random;
import Java.util.NavigableSet;
import Java.util.TreeSet;

/*
Average time for iteration of 1000 elements was 1,208 ns
*/
public class Main {
    public static void main(String... args) {
        doPerfTest(true);
        doPerfTest(false);
    }

    private static void doPerfTest(boolean warmup) {
        NavigableSet<MyData> set = new TreeSet<MyData>(new MyCompataror());
        Random random = new Random();
        for (int i = 0; i < 1000; i++) {
            set.add(new MyData("text-" + random.nextLong(), random.nextInt()));
        }
        MyData[] myDatas = set.toArray(new MyData[set.size()]);
        long start = System.nanoTime();
        final int runs = 500 * 1000;
        for (int i = 0; i < runs; i+=2) {
            // forward iteration
            for (MyData md : myDatas) {

            }
            // reverse iteration
            for (int j = myDatas.length - 1; j >= 0; j--) {
                MyData md = myDatas[j];
            }
        }
        long time = System.nanoTime() - start;
        if (!warmup)
            System.out.printf("Average time for iteration of 1000 elements was %,d ns", time / runs);
    }

    static class MyCompataror implements Comparator<MyData> {
        public int compare(MyData o1, MyData o2) {
            int cmp = o1.text.compareTo(o2.text);
            if (cmp != 0)
                return cmp;
            return o1.value > o2.value ? +1 :
                    o1.value < o2.value ? -1 : 0;
        }
    }

    static class MyData {
        String text;
        int value;

        MyData(String text, int value) {
            this.text = text;
            this.value = value;
        }
    }
}

ここでメインループをに置き換えると、平均時間は20,493になります。

// forward iteration
for(Iterator<MyData> it = set.iterator(); it.hasNext();) {
    MyData md = it.next();
}
// reverse iteration
for(Iterator<MyData> it = set.descendingIterator(); it.hasNext();) {
    MyData md = it.next();
}

これを毎回コピーを取ることと比較してみましょう(私が述べたように、変更された場合にのみコピーを取るほど最適ではありません)、時間は15,134 nsに低下します!

したがって、NavigableSetの使用は、説明した3つのオプションの最も遅いである可能性があります。

5
Peter Lawrey

TreeMap などのSortedMapを、並べ替え順序を逆にするカスタム Comparator で定義できます。両方向で反復する必要がある場合は、データ構造の2つのコピーをメモリに保持することが可能でしょうか?

2
Stephan202