使用自定义比较器时,使用TreeSet或ArrayList是否更好?

时间:2014-06-23 16:49:42

标签: java performance sorting arraylist set

我已经实现了一个图表。 我想根据它们的度数对给定的顶点子集进行排序。 因此,我编写了一个名为DegreeComparator的自定义比较器。

private class DegreeComparator implements Comparator<Integer>
{
    @Override
    public int compare(Integer arg0, Integer arg1) 
    {
        if(adj[arg1].size() == adj[arg0].size()) return arg1 - arg0;
        else return adj[arg1].size() - adj[arg0].size());
    }

}

那么,下面哪一项效率更高?

使用TreeSet

public Collection<Integer> sort(Collection<Integer> unsorted)
{
    Set<Integer> sorted = new TreeSet<Integer>(new DegreeComparator());
    sorted.addAll(unsorted);
    return sorted;
}

使用ArrayList

Collections.sort(unsorted, new DegreeComparator());

请注意,第二种方法不是函数,而是单行代码。

直观地说,我宁愿选择第二个。但我不确定它是否更有效率。

3 个答案:

答案 0 :(得分:41)

enter image description here Java API包含许多Collection和Map实现,因此可能会弄清楚要使用哪一个。这是一个快速的流程图,可能有助于从最常见的实现中进行选择

答案 1 :(得分:8)

TreeSet是一个Set。它删除重复项(具有相同程度的元素)。所以两者都不相同。

无论如何,如果你想要的是一个排序列表,那么对列表进行排序。无论集合是否具有重复,这都将起作用,即使它具有与填充TreeSet相同的复杂度(O(n * log(n)),它也可能更快(因为它只需要移动数组中的元素,而不是必须创建大量的树节点。)

答案 2 :(得分:3)

如果您只排序一次,则ArrayList显然是赢家。如果您经常添加或删除项目,再次排序列表,那么TreeSet会更好。

另请注意,所有树结构都需要更多内存和内存访问间接,这会使它们变慢。


如果中等大小的列表(由单个元素频繁更改),最快的解决方案可能是使用ArrayList并插入正确的位置(显然假设数组最初排序)。

您需要通过Arrays.binarySearch确定插入位置并插入或移除。实际上,我不会这样做,除非性能真的很关键,而基准测试会显示它有帮助。当列表变得非常大并且因为Java使用TimSort时,它会变得很慢,这是针对这种情况进行优化的。


正如评论所指出的那样,确保Comparator返回不同的值有时并非易事。幸运的是,有#Guava的Ordering#arbitrary,如果你不需要与equals兼容,它就可以解决问题。如果你这样做,可以写一个类似的方法(我确定如果要求我可以在某处找到它。)