【发布时间】:2009-03-16 22:05:22
【问题描述】:
我需要向后遍历 SortedMap 的条目集(即 SortedSet)。我正在编写的代码对性能非常敏感,因为每秒会从许多地方调用它数千次,甚至更多。对最快的方式有什么建议吗?
【问题讨论】:
-
你的意思是,你需要向前迭代它和向后?否则,只需反转您的比较器。
标签: java collections
我需要向后遍历 SortedMap 的条目集(即 SortedSet)。我正在编写的代码对性能非常敏感,因为每秒会从许多地方调用它数千次,甚至更多。对最快的方式有什么建议吗?
【问题讨论】:
标签: java collections
在 Java 1.6 中,您可以使用 NavigableSet。
【讨论】:
在填写地图之前使用它:
SortedMap sortedMap = new TreeMap(java.util.Collections.reverseOrder());
【讨论】:
迭代集合的更快方法是获取它的数组副本。这可以在不创建对象甚至方法调用的情况下向前和向后迭代。缺点是你需要在它发生变化时更新它以及你的集合。
在以下示例中,向前或向后迭代超过 1000 个元素平均需要 1,208 ns。
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 可能是所讨论的三个选项中最慢的。
【讨论】:
您可以使用自定义 Comparator 来定义一个 SortedMap(例如 TreeMap),以反转排序顺序。如果您需要双向迭代,那么在内存中保留 两个 数据结构副本是否可行?
【讨论】: