在JAVA中排序没有重复的集合

时间:2013-12-20 11:26:37

标签: java treeset

我需要使用自定义比较器订购一个集合而不在内存中复制它。

天真的实施将是:

Set<MyClass> newSet = new TreeSet<>(myComparator);
newSet.addAll(oldSet);

但这意味着,即使在有限的时间内,我也会在内存中有两个集合:oldSet(无序)和newSet(有序)。由于它们非常大,我想避免这种情况。

我想做这样的事情:

oldSet = new TreeSet<>(oldSet, myComparator);

实际上是不可能的,因为没有TreeSet的构造函数具有这样的结构。

这可能是一个解决方案吗?

Iterator<MyClass> it = oldSet.iterator();
Set<MyClass> newSet = new TreeSet<>(myComparator);
while(it.hasNext())
{
    newSet.add(it.next());
    it.remove();
}       

更好的建议?

谢谢

5 个答案:

答案 0 :(得分:2)

使用TreeSet对内存效率最高,并不是最快的方法。

您应该使用ArrayList并对其执行排序:

List<MyClass> sorted = new ArrayList<>(oldSet.size());
oldSet = null;
Collections.sort(sorted, myComparator);

ArrayList中使用的单个数组的开销不应成为问题,无论如何,这是您可以拥有的最小问题。

单次批量排序操作比为TreeSet中的每个单独项目找到正确的位置更快,以及在这种情况下所需的所有分配。

答案 1 :(得分:0)

由于Set未按定义排序,因此无法订购Set,因此(如果您这样做)您必须使用有序数据结构。但是,您根本不需要关心您看到的问题,如果执行Set,Java将不会执行addAll的深层副本,它只会复制几乎不使用RAM的引用。< / p>

所以你的addAll解决方案是一个干净而正确的解决方案。

答案 2 :(得分:0)

如果你可以将所有对旧集合的引用置零,那就

newSet.addAll(oldSet);
oldSet = null;

如果你不能将所有对旧集的引用置零,请使用Set.clear方法

newSet.addAll(oldSet);
oldSet.clear();

请注意,在清除HashSet的内部哈希表后不收缩

答案 3 :(得分:0)

在构造函数中创建set时使用set,可以创建吞下副本。您只复制参考。删除时也会删除引用。它在以下代码中可见:

MyComparator myComparator = new MyComparator();
Set<Object> newSet = new TreeSet<>(myComparator);
Object mc = new Object();
newSet.add(mc); //set is created

Set<Object> newerSet = new TreeSet<>(myComparator);
newerSet.addAll(newSet);
System.out.println(newSet);
System.out.println(newerSet);

输出: [java.lang.Object@1bb1deea] [java.lang.Object@1bb1deea]

引用同一个对象。

newerSet.remove(mc);
System.out.println("After deletion");
System.out.println(newSet);
System.out.println(newerSet);

删除后 [java.lang.Object@1bb1deea] []

仅删除引用。

答案 4 :(得分:0)

您应该编写一个Iterator实现,其中每次调用next()都会为您提供下一个已排序的项目。它不会占用额外的内存,但与复制无序Set相比,额外内存量会很小。您也没有新的Set,但您可以遍历它。

低内存版本,但效率低下的算法会将最近访问过的项目存储在Iterator中。每当您需要返回下一个项目时,您都会检查后备Set中的所有项目,以确定下一个项目。