java - 为什么对此 Treeset 的删除调用不能有效删除元素?

标签 java

我之前尝试编写 Dijkstra 算法,但在实现中遇到了问题。我终于找到了解决方案,但仍然对代码的行为感到困惑。

我在这里尝试做的是迭代地标记树集的元素。每次标记一个元素时,我都会将其从集合中删除并重新插入,因此集合将其放置在集合的末尾(正如 compareTo 方法告诉它的那样)。 这样做,我可以在 while 循环中获取集合的第一个元素,并在第一个元素被标记时停止。

以下示例是一个最小示例:

public static void main(final String[] args) {
    Set<Element> elements = new TreeSet<>();
    elements.add(new Element(1));
    elements.add(new Element(2));
    elements.add(new Element(3));
    elements.add(new Element(5));
    elements.add(new Element(4));
    System.err.println(elements.size());
    while(!elements.iterator().next().mark){
        Element element = elements.iterator().next();
        element.mark();
        elements.remove(element);
        elements.add(element);
    }
    System.err.println(elements.size());
}

private static class Element implements Comparable<Element>{

    private boolean mark = false;
    private final int id;

    public Element(int id){
        this.id = id;
    }

    public void mark(){
        this.mark = true;
    }

    @Override
    public boolean equals(Object o){
        Element other = (Element) o;
        if(this.mark == other.mark){
            return this.id == other.id;
        } else {
            return false;
        }
    }

    @Override
    public int compareTo(Element other){
        if(this.mark == other.mark){
            return this.id - other.id;
        } else if(this.mark && !other.mark){
            return 1;
        } else {
            return -1;
        }
    }
}

这里的问题是这一行:

elements.remove(element);

删除该元素。但是,在调试器中运行它,我可以看到该元素与集合中的元素具有完全相同的引用,并且就 equals 方法而言等于它。因此,运行该行时:

elements.add(element);

相同的元素被添加两次;因为我认为树集中的插入使用二分搜索,并且不测试集合的第一个元素和新插入的元素之间的相等性。

我明白交换两行:

element.mark();
elements.remove(element);

确实解决了问题。

我的问题是:为什么在通过迭代器修改时,树集的修改元素没有被有效删除?

最佳答案

TreeSet 使用 compareTo 来定位树结构中的元素(并确定相等性)。如果您将一个元素放入 TreeSet 中,然后修改 compareTo 方法中使用的属性(即您案例中的标记),remove 无法找到该元素,因为它在与插入原始元素的位置不同的位置中查找该元素。

如果在更改元素之前删除该元素,则可以解决问题,因为在插入元素时会找到原始元素。

关于java - 为什么对此 Treeset 的删除调用不能有效删除元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33757097/

相关文章:

java - 是否可以从本地应用程序使用 Google Datastore?

java - spring SQL Injection中的@Query注解安全吗?

java - 文本分析中如何消除文本文件中的空格?

java - 在 LoginContext 类中提交身份验证时,LDAP 身份验证不起作用

java - 从字符串中删除单词(使用特定方法时)

java - 使用 java 连接到远程 mongodb 服务器

java - 从 Selenium Webdriver 的下拉列表中选择选项时忽略大小写

java - 快速 Activity 切换导致应用程序崩溃

java - 将图像转换为草图然后卡通化?

java - 对于以下从时间戳中删除纳秒和秒组件的快速方法,是否存在任何可能失败的边缘情况?