简体   繁体   English

使用自定义比较器时最好使用TreeSet或ArrayList

[英]Is it better to use a TreeSet or ArrayList when using a custom comparator

I have implemented a graph. 我已经实现了一个图形。 I want to sort a given subset of vertices with respect to their degrees. 我想针对其度对给定的顶点子集进行排序。 Therefore, I've written a custom comparator named DegreeComparator . 因此,我编写了一个自定义比较器,命名为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());
    }

}

So, which one of the below is more efficient? 那么,以下哪一项更有效?

Using TreeSet 使用TreeSet

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

Using ArrayList 使用ArrayList

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

Notice that the second approach is not a function, but a one-line code. 注意,第二种方法不是函数,而是单行代码。

Intuitively, I'd rather choose the second one. 凭直觉,我宁愿选择第二个。 But I'm not sure if it is more efficient. 但是我不确定它是否更有效。

在此处输入图片说明 Java API contains numerous Collection and Map implementations so it might be confusing to figure out which one to use. Java API包含许多Collection和Map实现,因此弄清楚要使用哪个实现可能会造成混淆。 Here is a quick flowchart that might help with choosing from the most common implementations 这是一个快速流程图,可能有助于从最常见的实现中进行选择

A TreeSet is a Set. TreeSet是一个Set。 It removes duplicates (elements with the same degree). 它将删除重复项(具有相同程度的元素)。 So both aren't equivalent. 因此,两者并不等同。

Anyway, if what you want naturally is a sorted list, then sort the list. 无论如何,如果您自然需要排序列表,则对列表进行排序。 This will work whether the collection has duplicates or not, and even if it has the same complexity (O(n*log(n)) as populating a TreeSet, it is probably faster (because it just has to move elements in an array, instead of having to create lots of tree nodes). 无论集合是否重复,这都将起作用,即使它的复杂度(O(n * log(n))与填充TreeSet相同),也可能更快(因为它只需要移动数组中的元素,而不需要创建很多树节点)。

If you only sort once, then the ArrayList is an obvious winner. 如果仅排序一次,则ArrayList无疑是赢家。 The TreeSet is better if you add or remove items often as sorting a list again and again would be slow. 如果您经常添加或删除项目,则TreeSet会更好,因为一次又一次地对列表进行排序会很慢。

Note also that all tree structures need more memory and memory access indirection which makes them slower. 还要注意,所有树结构都需要更多的内存和间接访问内存的方法,这会使它们变慢。


If case of medium sized lists, which change rather frequently by a single element, the fastest solution might be using ArrayList and inserting into the proper position (obviously assuming the arrays get sorted initially). 如果中型列表的情况经常由单个元素更改,则最快的解决方案可能是使用ArrayList并将其插入适当的位置(显然是假设数组最初已排序)。

You'd need to determine the insert position via Arrays.binarySearch and insert or remove. 您需要通过Arrays.binarySearch确定插入位置,然后插入或移除。 Actually, I would't do it, unless the performance were really critical and a benchmark would show it helps. 实际上,除非性能非常关键,并且基准测试表明它会有所帮助,否则我不会这样做。 It gets slow when the list get really big and the gain is limited as Java uses TimSort , which is optimized for such a case. 当列表很大时,它会变慢,并且增益受到限制,因为Java使用了针对这种情况进行了优化的TimSort


As pointed in a comment, assuring that the Comparator returns different values is sometimes non-trivial. 正如评论中指出的那样,确保Comparator返回不同的值有时并非易事。 Fortunately, there's Guava's Ordering#arbitrary , which solves the problem if you don't need to be compatible with equals . 幸运的是,有番石榴的Ordering#arbitrary ,如果您不需要与equals兼容,它可以解决此问题。 In case you do, a similar method can be written (I'm sure I could find it somewhere if requested). 如果您这样做,可以编写类似的方法(如果需要,我敢肯定我可以在某个地方找到它)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM