LinkedHashSet的HashSet不会删除包含多个元素

时间:2015-12-24 14:41:08

标签: java collections hashset linkedhashset

我正在学习数据结构和算法,并试图在Java中实现不相交的数据结构。这是我的代码 -

import java.util.*;

public class DisjointSet<T> {
    Set<LinkedHashSet<T>> allSets;

    DisjointSet()   {
        allSets = new HashSet<LinkedHashSet<T>>();
    }

    public void makeSet(T t)    {
        Iterator itr = allSets.iterator();
        while (itr.hasNext())   {
            LinkedHashSet set = (LinkedHashSet) itr.next();
            if (set.contains(t))    {
                return;
            }
        }

        LinkedHashSet<T> set = new LinkedHashSet<T>();
        set.add(t);

        allSets.add(set);
    }

    public T findSet(T t)   {       
        Iterator itr = allSets.iterator();
        while (itr.hasNext())   {
            LinkedHashSet set = (LinkedHashSet) itr.next();
            if (set.contains(t))    {
                Iterator itr1 = set.iterator();
                T t1 = (T) itr1.next();
                return t1;
            }
        }

        return null;
    }

    public void union(T t1, T t2)   {
        LinkedHashSet<T> set1 = null, set2 = null;

        Iterator itr = allSets.iterator();
        while (itr.hasNext())   {
            LinkedHashSet set = (LinkedHashSet) itr.next();
            if (set.contains(t1))   {
                set1 = (LinkedHashSet<T>) set;
                System.out.println("Got set1:: " + set1);
            } else if (set.contains(t2))    {
                set2 = (LinkedHashSet<T>) set;
                System.out.println("Got set2:: " + set2);
            }
        }

        if (null != set1)   {
            System.out.println("Adding set2 to set1");
            set1.addAll(set2);

            if (null != set2)   {
                System.out.println("Removing set2");
                System.out.println(allSets.remove(set2));
            }
        }
    }

    public void viewAllSets()   {
        System.out.println(this.allSets);
    }
}

这是我正在运行的代码来测试我的实现 -

public class DisjointTest   {   
    public static void main(String [] args) {
        DisjointSet<Integer> dsets = new DisjointSet<Integer>();

        dsets.makeSet(30);
        dsets.makeSet(600);
        dsets.makeSet(20);
        dsets.makeSet(25);
        dsets.makeSet(90);
        dsets.makeSet(100);
        dsets.makeSet(1);

        dsets.viewAllSets();
        System.out.println();

        System.out.println(dsets.findSet(25));

        dsets.union(20, 25);
        dsets.viewAllSets();

        System.out.println();

        System.out.println(dsets.findSet(25));

        dsets.union(1, 100);
        dsets.viewAllSets();

        System.out.println();

        dsets.union(20, 100);
        dsets.viewAllSets();

        System.out.println(dsets.findSet(100));

        System.out.println();

        dsets.union(30, 90);
        dsets.viewAllSets();

        System.out.println();

        dsets.union(1, 90);
        dsets.viewAllSets();
    }   
}

当我尝试将一个集合与另一个集合合并,比如说set2,它有2个或更多元素时,集合会正确合并,但即使在调用allsets.remove(set2)之后,set2也不会从集合集合中删除

但是,如果要合并的集合,即; set2只有1个元素,allSets.remove(set2)成功地从集合集合中删除了set2。

以下是我的代码的输出,它确认了我的问题 -

[[1], [100], [20], [25], [600], [90], [30]]

25
Got set1:: [20]
Got set2:: [25]
Adding set2 to set1
Removing set2
true
[[1], [100], [20, 25], [600], [90], [30]]

20
Got set1:: [1]
Got set2:: [100]
Adding set2 to set1
Removing set2
true
[[1, 100], [20, 25], [600], [90], [30]]

Got set2:: [1, 100]
Got set1:: [20, 25]
Adding set2 to set1
Removing set2
false
[[1, 100], [20, 25, 1, 100], [600], [90], [30]]
1

Got set1:: [20, 25, 1, 100]
Got set2:: [90]
Adding set2 to set1
Removing set2
true
[[1, 100], [20, 25, 1, 100, 90], [600], [30]]

我无法理解为什么HashSet.remove(LinkedHashSet)无法删除包含多个元素的LinkedHashSet,但成功删除了包含1个元素的LinkedHashSet

任何帮助都将受到高度赞赏。 非常感谢你。

2 个答案:

答案 0 :(得分:4)

您错过了使用集合的关键点:您不能修改存储在集合中的值(至少不能改变其相等性)。

如果修改已存储在HashSet中的值,并且该修改更改了值的hashCode,则无法再在该集合中找到该值,因为它不再位于与其hashCode对应的存储桶中。

将一个集合与另一个集合时,您更改其hashCode,从而完全破坏整个数据结构的正确性。

示例:

  1. 创建一个LinkedHashSet inner1,其中包含1. hashCode为5
  2. 将其存储在outerSet
  3. outerSet在bucket 5中存储inner1,因为它的hashCode是5
  4. 将2添加到inner1。现在它的hashCode变为3。
  5. 从外套中移除inner1。
  6. outerSet获取inner1的hashCode以找到存储inner1的存储桶:3
  7. outerSet尝试在存储桶3中查找inner1。什么也没找到,因为它存储在存储桶5中。
  8. 请注意,TreeSet也是如此。 TreeSet通过构造值树来工作:如果A小于root,则它转到左分支。如果修改A并且它变得比root大,TreeSet将尝试在树的错误分支中找到它。

答案 1 :(得分:0)

至于其他人的理论基础已经回答。

就解决方案使用好的ol矢量并避免花哨的smanchy hashsets而言 - 如果你去了hashsets,你在数学上理解它的集合的想法会被破坏

import java.util.*;

public class DisjointSet<T> {
Vector allSets;

DisjointSet()   {
    allSets = new Vector();
}

public void makeSet(T t)    {
    Iterator itr = allSets.iterator();
    while (itr.hasNext())   {
        Vector set = (Vector) itr.next();
        if (set.contains(t))    {
            return;
        }
    }

    Vector set = new Vector();
    set.add(t);

    allSets.add(set);
}

public T findSet(T t)   {       
    Iterator itr = allSets.iterator();
    while (itr.hasNext())   {
        Vector set = (Vector) itr.next();
        if (set.contains(t))    {
            Iterator itr1 = set.iterator();
            T t1 = (T) itr1.next();
            return t1;
        }
    }

    return null;
}

public void union(T t1, T t2)   {
    Vector set1 = null, set2 = null;

    Iterator itr = allSets.iterator();
    while (itr.hasNext())   {
        try {
        Vector set = (Vector) itr.next();
        if (set.contains(t1))   {
            set1 = (Vector) set;
            System.out.println("Got set1:: " + set1);
        } else if (set.contains(t2))    {
            set2 = (Vector) set;
            System.out.println("Got set2:: " + set2);
        }
        }
        catch(Exception e) { e.printStackTrace(); }
    }

    if (null != set1)   {
        System.out.println("Adding set2 to set1");
        set1.addAll(set2);

        if (null != set2)   {
            System.out.println("Removing set2");
    viewAllSets();
            System.out.println(allSets.contains(set2)+" "+allSets.remove(set2));
        }
    }
}

public void viewAllSets()   {
    System.out.println(this.allSets);
}

public static void main(String [] args) {
    DisjointSet<Integer> dsets = new DisjointSet<Integer>();

    dsets.makeSet(30);
    dsets.makeSet(600);
    dsets.makeSet(20);
    dsets.makeSet(25);
    dsets.makeSet(90);
    dsets.makeSet(100);
    dsets.makeSet(1);

    dsets.viewAllSets();
    System.out.println();

    System.out.println(dsets.findSet(25));

    dsets.union(20, 25);
    dsets.viewAllSets();

    System.out.println();

    System.out.println(dsets.findSet(25));

    dsets.union(1, 100);
    dsets.viewAllSets();

    System.out.println();

    dsets.union(20, 100);
    dsets.viewAllSets();

    System.out.println(dsets.findSet(100));

    System.out.println();
}   

}