在Java中反向迭代SortedSet/SortedMap的最佳方法

在Java中反向迭代SortedSet/SortedMap的最佳方法,java,collections,Java,Collections,我需要向后遍历SortedMap的条目集(这是一个SortedSet)。我正在编写的代码对性能非常敏感,因为它将在许多地方每秒被调用数千次,甚至更多。关于如何以最快的方式执行此操作,有什么建议吗?您可以定义一个SortedMap,例如一个带有反转排序顺序的自定义映射。如果需要在两个方向上进行迭代,那么在内存中保留两个数据结构副本可能是可行的?迭代集合的更快方法是获取集合的数组副本。这可以在不创建对象甚至方法调用的情况下向前和向后迭代。缺点是,每当它发生变化时,您需要更新它以及您的收藏 在下面的示

我需要向后遍历SortedMap的条目集(这是一个SortedSet)。我正在编写的代码对性能非常敏感,因为它将在许多地方每秒被调用数千次,甚至更多。关于如何以最快的方式执行此操作,有什么建议吗?

您可以定义一个SortedMap,例如一个带有反转排序顺序的自定义映射。如果需要在两个方向上进行迭代,那么在内存中保留两个数据结构副本可能是可行的?

迭代集合的更快方法是获取集合的数组副本。这可以在不创建对象甚至方法调用的情况下向前和向后迭代。缺点是,每当它发生变化时,您需要更新它以及您的收藏

在下面的示例中,向前或向后迭代1000个元素平均需要1208 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;
        }
    }
}
import java.util.Comparator;
导入java.util.Random;
导入java.util.NavigableSet;
导入java.util.TreeSet;
/*
1000个元素的平均迭代时间为1208 ns
*/
公共班机{
公共静态void main(字符串…参数){
doperfest(真);
doperfest(假);
}
专用静态无效DoperTest(布尔预热){
NavigableSet集合=新树集合(新MyCompatar());
随机=新随机();
对于(int i=0;i<1000;i++){
添加(新的MyData(“text-”+random.nextLong(),random.nextInt());
}
MyData[]myDatas=set.toArray(新的MyData[set.size()]);
长启动=System.nanoTime();
最终整数运行=500*1000;
对于(int i=0;i=0;j--){
MyData md=myDatas[j];
}
}
长时间=System.nanoTime()-开始;
如果(!预热)
System.out.printf(“1000个元素的平均迭代时间为%,d ns”,时间/运行次数);
}
静态类MyCompatar实现Comparator{
公共整数比较(MyData o1、MyData o2){
int cmp=o1.text.compareTo(o2.text);
如果(cmp!=0)
返回cmp;
返回o1.value>o2.value?+1:
o1.值
现在用替换主循环,平均时间变为20493

// 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();
}
//正向迭代
for(Iterator it=set.Iterator();it.hasNext();){
MyData md=it.next();
}
//反向迭代
for(迭代器it=set.degendingIterator();it.hasNext();){
MyData md=it.next();
}
现在,让我们将其与每次复制进行比较(我已经说过,这并不像只在更改时复制那样理想),时间下降到15134纳秒


因此,使用NavigableSet可能是讨论的三个选项中最慢的一个。

在Java 1.6中,您可以使用。

在填充地图之前使用以下选项:

SortedMap sortedMap = new TreeMap(java.util.Collections.reverseOrder());

你是说,你需要前后迭代?否则,只需反转您的比较器。数组复制-每次方法调用,每秒超过1000次?!:)当然在Java中,复制数组大约是最快的事情。短基准测试:复制一个包含1000个对象的SortedSet和一个反转排序顺序的自定义比较器大约需要0.8毫秒。这不仅是一个副本,而且还反转排序顺序。所以,是的,它很快。我说“当它改变时,你需要更新它以及你的集合。”不是每个方法调用。如果数组已经排序,则不需要对其进行反向排序。对包含1000个元素的已排序集执行toArray()只需不到14微秒的时间(您不需要经常这样做),我不知道如何得到0.8毫秒;)NavigableSet下降迭代器()是的。具体来说,使用NavigableSet.DegendingIterator()。或者可以使用NavigableSet.degendingset()以现有集合支持的相反顺序获取元素视图,这两个接口的作者,Java 6中引入NavigableSet的主要原因之一是能够以相反的顺序轻松迭代。能否给出一个代码示例,说明如何借助NavigableSet迭代SortedSet?分别用NavigableSet和NavigableSet替换SortedMap和SortedSet接口。严格地说,仅使用SortedSet是不可能的。(您可能知道底层实现支持NavigableMap并使用强制转换,但这将是一个相当糟糕的攻击,并且在实现更改时可能会中断。)谢谢!添加它要比将实现更改为NavigableSet容易得多。