简体   繁体   中英

HashSet of LinkedHashSets does not delete LinkedHashSet with multiple elements

I am learning Data Strucrtures and Algorithms, and trying to implement disjoint-set data structure in Java. Here is my code to do the same-

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);
    }
}

And here is the code I am running to test my implementation-

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();
    }   
}

When I try to merge a set with anther one, say set2, which has 2 or more elements, the sets get merged properly but set2 is not removed from the collection of sets even after calling allsets.remove(set2)

But, if the set to be merged, ie; set2, has only 1 elements, allSets.remove(set2) successfully removes set2 from the collection of sets.

Here is the output of my code which confirms my problem-

[[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]]

I am not able to comprehend why HashSet.remove(LinkedHashSet) is not able to remove a LinkedHashSet with multiple elements, but successfully removes a LinkedHashSet with 1 element.

Any help will be highly appreciated. Thank you very much.

You're missing a key point of using sets: the values you store in a Set must NOT be modified (at least not in a way that changes its equality).

If you modify a value that has been stored in a HashSet, and that modification changes the value's hashCode, then the value can't be found in the set anymore, since it's not in the bucket that corresponds to its hashCode anymore.

When merging a set with another one, you change its hashCode, and thus completely break the correctness of the whole data structure.

Example:

  1. create a LinkedHashSet inner1 containing 1. hashCode is 5
  2. Store it in outerSet
  3. outerSet stores inner1 in bucket 5, because it's hashCode is 5
  4. Add 2 to inner1. Now its hashCode becomes 3.
  5. Remove inner1 from outer set.
  6. outerSet gets the hashCode of inner1 to find the bucket where inner1 is stored: 3
  7. outerSet tries to find inner1 in bucket 3. Finds nothing, because it's stored in bucket 5.

Note that the same goes for TreeSets. TreeSets work by constructing a tree of values: if A is smaller than root, then it goes to the left branch. If you modify A and it becomes bigger than root, the TreeSet will tryy to find it in the wrong branch of the tree.

As far as the theoretical underpinning the other guys have answered.

As far as a solution use good ol vectors and avoid fancy smanchy hashsets - the idea of a set as you understand it mathematically is destroyed if you go to 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();
}   

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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