首页 > 解决方案 > 由于逻辑错误,允许相同的树集值

问题描述

大家好,我现在正在学习 java 集合并有这个任务。我的逻辑有问题,谁能告诉我我哪里出错了?这是我的代码。

这是我实例化母亲树集的家庭类

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class Family {
    Mother mom = new Mother("0", 0, 0);

    Set<Mother> Mothers = new TreeSet<Mother>(new Comparator<Mother>() {
        public int compare(Mother a, Mother b) {
            if(a.getName().compareTo(b.getName()) == 0) return 0;

            if(a.getMonth() == b.getMonth()){
                if(a.getDay() > b.getDay()) return 1;

                else if(a.getDay() < b.getDay()) return -1;
            }
            if(a.getMonth() > b.getMonth()) return 1;

            if(a.getMonth() < b.getMonth()) return -1;

            return a.getName().compareTo(b.getName());
        }
    });

    public Family(){}

    public boolean addMother(java.lang.String name, int day, int month)
    {
        Mother a = new Mother(name, day, month);
        return Nieces.add(a);
    }
}

这是我分配母亲 TreeSet 的主类。

public class Main {
    public static void main(String[] args) {
       Family myFam = new Family();
       myFam.addMother("Tokyo", 1, 3);
       myFam.addMother("Shaline", 1, 1);
       myFam.addMother("Betty", 2, 3);
       myFam.addMother("Amy", 1, 1);
       myFam.aaddMother("Shaline", 4, 3);
       System.out.println(myFam.Mothers);
    }
}

所以我想按日期和月份对其进行排序。我得到的输出是:[Amy, Shaline, Tokyo, Betty, Shaline] 这是正确的,因为它是根据日期和月份排序的,但我预计它只会是一个 Shaline因为它是一个树集。我该怎么做才能输出:[Amy, Shaline, Tokyo, Betty]。我也已经试过了if(a.getName().equals(b.getName())) return 0;

但它仍然无法正常工作。谢谢您的帮助!

标签: javacollectionscomparatortreeset

解决方案


您的比较器不一致。请参阅比较器的合同

实现者还必须确保关系是可传递的:
((compare(x, y)>0) && (compare(y, z)>0))蕴含compare(x, z)>0

您的比较器违反了这一点,例如 when xis"Shaline", 1, 1yis "Betty", 2, 3,它正在报告z并使用月份或日期,因此传递性规则将要求,但由于名称相同,您的比较器通过返回零来报告。"Shaline", 4, 3x < yy < zx < zx == z

依赖于传递性,TreeSet因为它允许有效查找,通过不将每个元素与插入时的新元素进行比较,而是使用顺序导航到树中的正确位置。

您可以添加一个线性搜索,就像在这个答案中一样,但这会降低效率,Set因为它现在比较每个包含的元素。

相反,我推荐类似的东西:

Set<String> names = new HashSet<>();
Set<Mother> mothers = new TreeSet<>(Comparator.comparingInt(Mother::getMonth)
        .thenComparingInt(Mother::getDay).thenComparing(Mother::getName));

public Family(){}

public boolean addMother(java.lang.String name, int day, int month)
{
    return names.add(name) && mothers.add(new Mother(name, day, month));
}

这简化并修复了比较器,它现在始终使用Mother对象的所有属性并添加了有效的预测试。


推荐阅读