繁体   English   中英

带有自定义比较器的 TreeSet() 的异常行为

[英]Anomalous behaviour with TreeSet() with custom comparator

我在下面的程序中所做的是,我创建了一个名为“alls”的 TreeSet,它带有一个自定义比较器,它比较两个列表,如果它们相等则返回 0,否则返回 1。但是如果我将两个相同的列表添加到 TreeSet 中然后 TreeSet 接受两个相同的列表。 但它不应该包含两个相同的列表,因为我已经定义了一个这样的比较器。

   List<Integer> a1 = new ArrayList<Integer>() {{add(1);add(2);add(3);add(4);}};
    List<Integer> a2 = new ArrayList<Integer>() {{add(1);add(1);}};
    List<Integer> a3 = new ArrayList<Integer>() {{add(2);add(1);}};
    List<Integer> a4 = new ArrayList<Integer>() {{add(3);add(1);}};
    List<Integer> a5 = new ArrayList<Integer>() {{add(4);add(1);}};
    List<Integer> a6 = new ArrayList<Integer>() {{add(5);add(1);}};
    
    Comparator b1 = (l1,l2)->{if(l1.equals(l2)) return 0; else return 1;};
    Collection<List<Integer>> alls = new TreeSet(b1);
    alls.add(a1);
    alls.add(a1);
    alls.add(a1);
    alls.add(a2);
    alls.add(a3);
    alls.add(a1);
    alls.add(a4);
    alls.add(a6);
    alls.add(a5);
    alls.add(a2);
    alls.add(a1);

当我尝试打印我的 TreeSet(name alls) 时,会显示以下输出:

1 2 3 4

1 1

2 1

1 2 3 4

3 1

5 1

4 1

您可以看到 [1 2 3 4] 两次插入到我的 TreeSet(其名称为 alls)中,但之后没有插入。

这怎么可能? 我虽然带有我的自定义比较器的 TreeSet 不允许重复。 此外,如果它允许为什么不在我的程序中进一步插入相同的元素

你的比较器不工作

Collection<List<Integer>> alls = new TreeSet(b1);
alls.add(a1);
alls.add(a2);
alls.add(a3);

由于return 1 ,您的实现对两个不同的列表进行排序,第二个总是更大,因此您的树看起来像:

a1 <- a3 -> a2

现在让我们添加 a1 :

Collection<List<Integer>> alls = new TreeSet(b1);
alls.add(a1);
alls.add(a2);
alls.add(a3);
alls.add(a1);

a1 <- a3 ? a1 -> a2 结果 a1 更大
a1 <- a3 -> a2 ? a1 结果 a1 更大
a1 <- a3 -> a2 -> a1

你的树现在已经复制了 a1。
解决方案:使用评论中提到的正确Comparator

尝试这个:

        Comparator<List<Integer>> b1 = (l1, l2)->{

        if(l1.equals(l2)) {
            return 0;
        } else {
            if(l1.isEmpty())
                return 1;
            if(l2.isEmpty())
                return -1;

            int i = 0;
            while (l1.get(i).equals(l2.get(i))) i++;

            if(l1.get(i) > l2.get(i))
                return 1;
            else
                return -1;
        }};

当一个列表“低于”第二个列表时,您的比较器无法处理这种情况。 您的比较器仅返回 0 和 1。我认为 TreeSet 使用二分搜索或任何更快的方法来查找对象并检查特定对象是否为集合。 像这样的方法需要明确定义一个对象是大于还是小于其他对象。 如果 TreeSet 使用相等对象与集合中的每个对象进行原始比较,则您的比较器将起作用。 在排序结构中,找到对象的方法更复杂、更好。

暂无
暂无

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

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