【问题标题】:Java: Sorting TreeSets based on sizeJava:根据大小对树集进行排序
【发布时间】:2017-08-28 13:13:24
【问题描述】:

我正在寻找一种方法来对一组集合进行排序 - 更具体地说,数据结构需要具有以下属性:

  • “外部”和“内部”集合都应该是集合,即包含的集合中不应有重复的元素,也不应有重复的集合。
  • 集合应该按照包含集合的长度升序排序,即{{A}, {A, B}, {A, C, F}, {B, D, F}}有效而 {{A, C, F}, {A, B}, {B, D, F}, {A}} 不是。
  • 应该可以迭代单个包含的集合以及所有集合。当然,遍历所有集合应该根据它们各自的大小按升序列出它们。
  • 如果两个集合的大小相同,则顺序可能是任意的。

我的基本方法是TreeSet<TreeSet<T>>,尽管由于包含的 TreeSets 需要按照自定义行为进行排序,所以我编写了一个包装类(省略了不必要的细节,例如额外的构造函数和方法):

import java.util.TreeSet;
import java.util.Iterator;
import java.util.Collection;

public class WrappedSet< T > implements Comparable< WrappedSet< T >>, Iterable< T >  {
    protected TreeSet< T > set;

    public WrappedSet( Collection< T > collection ) {
        set = new TreeSet< T >( collection );
    }

    public int size() {
        return set.size();
    }

    @Override
    public Iterator< T > iterator() {
        return set.iterator();
    }

    @Override
    public int compareTo( WrappedSet< T > other ) {
        if ( set.equals( other.set )) {
            return 0;
        }
        else {
            return ( set.size() >= other.set.size()) ? 1 : -1;
        }
    }

    @Override
    public String toString() {
        return set.toString();
    }
}

为了展示问题,我使用了这个主函数:

public static void main( String[] args ) {
    TreeSet< WrappedSet< String >> wsets = new TreeSet< WrappedSet< String >>();

    for ( String arg : args ) {
        wsets.add( new WrappedSet< String >( new TreeSet< String >( Arrays.asList( arg.split( "," )))));
    }

    System.out.println( "Input sets: " + Arrays.toString( wsets.toArray()));
}

我明白,如果我的 .equals() 这个类是基于测试各个集合的相等性,我的 "类 [将具有] 与 equals 不一致的自然顺序",如CompareTo documentation 表示它。我也明白这可能是输出(有时)不正确的原因。考虑以下示例:

输入(命令行):A,B,E A,C,F B,D,F A A,B,E
输出:输入集:[[A], [A, B, E], [A, C, F], [B, D, F], [A, B, E]]

如您所见,{A, B, E} 出现了两次,我想这是因为 TreeSet 遍历树以找到具有该值的现有条目,但最终没有找到它,因为顺序元素的数量与它们的实际值无关 - 只有它们的大小。

我怎样才能以一致的方式实现所需的行为?请注意,这不是家庭作业。因此自然欢迎不基于 TreeSet 的解决方案。

【问题讨论】:

  • 当你定义一个可比较对象时,你必须确保对于所有集合,a.compareTo(b) 永远不会返回与b.compareTo(a) 相同的答案,除非它们相等(两者都必须返回 0) .您的 compareTo 违反了该规则(反对称)。
  • 您在 compareTo() 方法中使用了 TreeSet.equals()。这不是真的工作...您应该将equals 实现到您的班级WrappedSet,并改用它...
  • 当两个集合大小相等时,您的方法可能会返回 1。据我了解,您仍然没有“比较方法违反其一般合同”的事实!异常可能只是一个幸运的巧合。
  • @UsagiMiyamoto 我已经实现但省略了它。这基本上是我的 compareTo 的第一行,所以老实说,我看不出这会有什么帮助。
  • @M.Prokhorov 那是因为,正如我所说,当集合具有相同大小时,我不关心顺序。对我来说,重要的是它们是否作为集合相等,或者它们是否比其他集合更大或更小。问题是,当两组大小相同时,我不知道我应该做什么,尤其是在这种情况下顺序无关紧要的情况下。

标签: java sorting set


【解决方案1】:

为了让你的外部TreeSet 接受两个相同大小的不同集合作为不同的元素,即使你不关心它们的顺序,你也需要确定它们的排序顺序。否则,您的设置将无法按预期工作。

而不是内部TreeSets 的包装类,我想我更愿意只写一个比较器。但是请确保您的比较器在内部集合上定义了一个总排序,并且只声明两个集合相等,它们确实是相等的,因为它们中只有一个应该在集合中。正如 RealSkeptic 和其他人在 cmets 中所说,为了履行Comparator 合同,您需要履行:

实施者必须确保sgn(compare(x, y)) == -sgn(compare(y, x)) 对所有xy

(来自the documentation

这只是一个非常粗略的Comparator 示例,当大小相同时,它确实比较的不仅仅是大小。设计一个仍然做得不够好的示例并不难,但我会留给您为您的情况编写正确的比较器。

    Comparator<TreeSet<?>> compareBySize 
            = Comparator.comparing((TreeSet<?> s) -> s.size())
                    .thenComparing(TreeSet::toString);

    TreeSet<TreeSet<Character>> mySet = new TreeSet<>(compareBySize);
    mySet.addAll(Arrays.asList(
                new TreeSet<>(Arrays.asList('A', 'B', 'E')),
                new TreeSet<>(Arrays.asList('A', 'C', 'F')),
                new TreeSet<>(Arrays.asList('B', 'D', 'F')),
                new TreeSet<>(Arrays.asList('A')),
                new TreeSet<>(Arrays.asList('A', 'B', 'E'))
            ));
    System.out.println(mySet);

打印出来

[[A], [A, B, E], [A, C, F], [B, D, F]]

我相信这是正确的。

顺便说一句,通常建议针对接口而不是实现进行编程。如果您想这样做,根据您的进一步要求,使用SortedSetNavigableSet 接口。您需要进行两项更改:首先,比较器应该是(在我的示例中使用 SortedSet):

    Comparator<SortedSet<?>> compareBySize 
            = Comparator.comparing((SortedSet<?> s) -> s.size())
                    .thenComparing(SortedSet::toString);

第二次将你的集合声明为SortedSet&lt;SortedSet&lt;Character&gt;&gt; mySet,但在实例化中仍然使用new TreeSet&lt;&gt;(…)

【讨论】:

    猜你喜欢
    • 2021-03-11
    • 2020-12-27
    • 2014-04-27
    • 2015-08-31
    • 2010-10-30
    • 2018-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多