Set in Java

Set:

HashSet:

1. It stores elements in Hashtable and its hierarchy shown below. Hashtable stores info in a mechanism called hashing. 
 In hashing, the informational content of a key is used to determine a unique value, called its hash code.
2. It stores unique elements(Why) and not order or position its elements.
3. It permits null values.
4.This class offers constant time performance for basic operations like add, remove, contains and size.
5.Iterating over this set required time proportional to the number of elements and number of hash map buckets.

Simple example can be like this:

import java.util.*;
class set {
public static void main(String args[])
{
HashSet<String> hs=new HashSet<String>();
hs.add("hello");
hs.add("genius");
Iterator<String> it=hs.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}

}


Output:

>javac set.java
>java set
hello
genius

HashSet methods:


Type          method name      Description

boolean      add(<E>)              Adds new element to HashSet
void            clear()                 Removes all of the elements from the HashSet
Object        clone()                 Returns the shallow copy of HashSet: Elements themselves   are not cloned
boolean      Contains(object o) Returns true  if the set contains specified element
boolean      isEmpty()               Returns true if this set contains no elements
Iterator<E> iterator()               Returns iterator over the elements in the list
boolean      remove(object o)   Removes the specified element
int              size()                     Returns the size of the list(it counts null item in the list)

All methods in one program:


import java.util.*;

public class set{
  public static void main(String [] args) { 
  int size;
  HashSet <String> hs= new HashSet <String>();
  String s="Java";
  hs.add("Hello");  
  hs.add(s); 
  hs.add("reader"); 
  hs.add("");//empty 
  System.out.print("Collection data: ");  
  Iterator iterator = hs.iterator(); 
  while (iterator.hasNext()){
  System.out.print(iterator.next() + " ");  
  }
  System.out.println();
  size = hs.size();
  if (hs.isEmpty()){
  System.out.println("Collection is empty");
  }
  else{
  System.out.println( "Collection size: " + size);
  }
  System.out.println();
  hs.remove(s);//s is an object.
  System.out.println("After removing ' java '\n");
  System.out.print("Now collection data: ");
  iterator = hs.iterator(); 
  while (iterator.hasNext()){
  System.out.print(iterator.next() + " ");  
  }
  System.out.println();
  size = hs.size();
  System.out.println("Collection size: " + size + "\n");
  hs.clear();
  size = hs.size();
  if (hs.isEmpty()){
  System.out.println("Collection is empty");
  }
  else{
  System.out.println( "Collection size: " + size);
  }
  }
}

How to sort HashSet?

import java.util.*;
public class sort{

public static void main (String args[]){
HashSet set = new HashSet();
set.add("Hello");
set.add("java");

set.add("Reader");
Set sortedSet= new TreeSet(set);
System.out.println(sortedSet);
} 
} 

Output:
>javac sort.java
>java sort
[Hello, Reader, java]

Hashset class supports four constructors:


1. HashSet(): It is a default constructor


2. 
HashSet(int capacity, float fillratio): fill ratio must be between 0.0 and 1.0.

HashSet exapansion= number of the elements greater than the capacity*fill ratio

3. HashSet(int capacity): the capacity grows automatically as the elements grows.

first three constructors creates empty sets of various sizes.

4. 
HashSet(Collection c)
it acts as copy constructor.

Methods:


boolean add(Object o);--adds unique element to hashset


void clear(); it clears all elements in the Hashset


Object clone(); it gives the shallow copy of the set; but elements themselves are not cloned


boolean contains(Object o): It returns true if the specified element is present in the set


boolean isEmpty(): it returns true if the set has no elements


Iterator iterator(): Returns an iterator over the elements in the set


boolean remove(Object o): it removes the specified element in the set


int size():  it returns the size of the set


Utility method:

toArray():  it is method inherited from Set interface used to convert the HashSet to arrray.

Set<String> stringSet = new HashSet<String>();
String[] strArray = stringSet.toArray();


EX:

import java.util.*;
class first
{
public static void main(String a[])
{
HashSet<String> hs=new HashSet<String>();
hs.add("Hello");
hs.add("java");
hs.add("learner");
String[] strArray=new String[hs.size()];
hs.toArray(strArray);
for(String str:strArray)
{
System.out.println(str);
}
}

}
Output:
>javac first.java
>java first
learner
java

Hello

How to copy content from one hashset to another?

import java.util.*;
class first
{
public static void main(String a[])
{
HashSet<String> hs=new HashSet<String>();
hs.add("Hello");
hs.add("java");
hs.add("learner");
HashSet<String> hs1=new HashSet<String>();
hs1.add("with");
hs1.add("passion");
hs.addAll(hs1);
System.out.println(hs);
}
}
Output:
>javac first.java
>java first
[with, learner, java, passion, Hello] (You may not get in this same order)

Compare two sets and retain the elements which are exists in both sets:

import java.util.*;
class first
{
public static void main(String a[])
{
HashSet<String> hs=new HashSet<String>();
hs.add("Hello");
hs.add("java");
hs.add("learner");
HashSet<String> hs1=new HashSet<String>();
hs1.add("with");
hs1.add("java");
hs1.add("learner");
hs.retainAll(hs1);
System.out.println(hs);
}

}
Output:
>javac first.java
>java first

[learner, java]

Example of containsAll method:
import java.util.*;
class first
{
public static void main(String a[])
{
ArrayList list=new ArrayList<String>();
list.add("Hello");
list.add("java");
list.add("learner");
HashSet<String> hs1=new HashSet<String>();
hs1.addAll(list);//It adds all the array list elements to HashSet(duplicate values can be removed after adding) 
boolean b=hs1.containsAll(list);//It returns true if list is in the hs1
System.out.println(b);
}
}
Output:
>javac first.java
>java first
true

Why HashSet doesn't allow duplicate values?


HashSet usually use HashMap to store the values of set internally. HashSet class is implemented like below in java API's.


Class definition goes here

{
    private transient HashMap<E,Object> map;
        // Dummy value to associate with an Object
    private static final Object PRESENT = new Object();
 public HashSet() {
        map = new HashMap<>();//set creates object to HashMap internally.
    }
        // SOME CODE goes here
public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
  }

1. Whenever you create an object to HashSet then it will create object to HashMap internally.

2. In HashMap each Key is unique. what we need to do is to pass the element E to the HashMap. This key is the value that we add through Hashset like hs.add(3). Here 3 is stored as key in HashMap. 
3. Usually HashMap accepts and stores the values as pairs (Key, value). Here in our discussion HashSet values are taken as keys where as value of those corresponding values can be assigned by the dummy value.
4. Then map.put(Key, value)--has two cases to be consider. 
     i. It returns null, If key is unique and added to the map
     ii. It returns old value key, if key is duplicate
5. But in HashSet add method we check map.put(key,value) method with null value(Hence it can only allow unique values).
that is stated above like: 
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
        }

An easy way to to add elements to set is:

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class MainClass {
public static void main(String[] a) {
String elements[] = { "Hello", "Mr.", "java", "Learner"};
Set set = new HashSet(Arrays.asList(elements));
System.out.println(set);
}
}

Output:
>javac MainClass.java
>java MainClass
[Mr., Learner, java, Hello]


To make a shallow copy of HashSet clone() method can be used: 

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class MainClass {
  public static void main(String[] a) {
    String elements[] = { "Learner", "Hello", "java", "Mr."};
    Set set = new HashSet(Arrays.asList(elements));
    Set set2 = ((Set) ((HashSet) set).clone());
    System.out.println(set2);
  }
}

Output:
>javac MainClass.java
>java MainClass
[Learner, java, Mr., Hello] 



LinkedHashSet:(It is introduced in JDK 1.4)


It maintains list of entries in the set, in the order in which they were inserted. This allows insertion-order(why) iteration over the set. It only contains unique values. LinkedHashSet uses LinkedHashMap object internally to store and process its elements. All the elements of LinkedHashSet are stored as keys in LinkedHashMap. LinkedHashSet doen't have its own methods. It only inherits HashSet methods.(Source code of LinkedHashSet)

 Key Point: It allows null values.

Example:

import java.util.*;

public class first{
public static void main(String a[])
{
LinkedHashSet<String> hs=new LinkedHashSet<String>();
hs.add("need");
hs.add("to");
hs.add("learn");
hs.add("more");
Iterator<String> it=hs.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
Output:
>javac first.java
>java first
need
to
learn
more

LinkedHashSet Constructors:

LinkedHashSet()


It creates empty linked hash set with the default initial capacity (16) and load factor (0.75).
LinkedHashSet(Collection c)
Creates a new linked hash set with the same elements as the specified collection.
LinkedHashSet(int initialCapacity)
It creates empty linked hash set with the specified initial capacity and the default load factor (0.75).
LinkedHashSet(int initialCapacity, float loadFactor)
           It creates empty linked hash set with initial capacity and load factor

Key Point: All the above constructors can call only one super class constructor. That super class constructor can only allow the capacity and load factor.

How LinkedHashSet maintains insertion order?
As already mentioned in the intro of LinkedHashSet, elements entered into LinkedHashSet are saved as keys in LinkedHashMap. Key, Value pairs are the instances of the static inner class of LinkedHashMap Entry<K,V>. This LinkedHashMap maintains before and after fields. These two fields makes LinkedHashMap to function as a doubly linked list.
Hence these two fields are responsible for insertion order in LinkedHashSet.(More)

When to use LinkedHashSet over HashSet?
LinkedHashSet can be used when we want to iterate over the elements as per the insertion order. If order does not matter, then we can go for HashSet.

Key Point: LinkedHashSet is  not synchronized but can be synchronized as 
Set st=Collections.synchronizedSet(LinkedHashSet());

TreeSet:

It same as HashSet and it doesn't allow duplicates. It implements NavigableSet and extends SortedSet. It maintains ascending order.

Simple example:
import java.util.*;
class test{
public static void main(String a[])
{
TreeSet<String> al=new TreeSet<String>();
al.add("hello");
al.add("java");
al.add("learner");
Iterator<String> it=al.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
Output:
>javac test.java
>java test
hello
java

learner

TreeSet supports four constructors:
TreeSet(): constructs empty TreeSet and arranges the elements in ascending order.
TreeSet(Collections c): constructs tree set that contains the elements of c
TreeSet(Comparator comp): Constructs empty constructor and sort depends on comp
TreeSet(SortedSet ss): Constructs tree set that contains the elements of SS

Methods that TreeSet inherits from its Parent class:

void add(Object o)-adds object to TreeSet
boolean addAll(Collection c)-adds all specified collection elements to this set
void clear()-removes all elements
Object clone()-returns shallow copy of TreeSet
Comparator comparator()-returns comparator used to order this sorted set otherwise null


boolean contains(Object o)-Returns true if this set contains the specified element.
Object first()-Returns the first (lowest) element
SortedSet headSet(Object toElement)-Returns a view of the portion of this set whose elements are strictly less than toElement.
boolean isEmpty()-Returns true if this set contains no elements.
Iterator iterator()-Returns an iterator over the elements
Object last()-Returns the last (highest) element currently in this sorted set.
boolean remove(Object o)-Removes the specified element from this set if it is present.
int size()-Returns size of the set
SortedSet subSet(Object fromElement, Object toElement)-Returns a view of the portion of this set whose elements range from fromElement(inclusive to) toElement (exclusive)
SortedSet tailSet(Object fromElement)-Returns a view of the portion of this set whose elements are greater than/equal to fromElement.

Ex: 1

import java.util.TreeSet;
public class Test {
    public static void main(String a[]){
        TreeSet<Integer> Ts = new TreeSet<Integer>();
        Ts.add(1);
        Ts.add(2);
        Ts.add(3);
        System.out.println("Elements: "+Ts);
        System.out.println("Is set empty: "+Ts.isEmpty());//check is set empty?
        Ts.clear();//remove all elements from set
        System.out.println("Is set empty: "+Ts.isEmpty());
        Ts.add(1);
        Ts.add(2);
        Ts.add(3);
        System.out.println("Size of the set: "+Ts.size());
        Ts.remove(2);//remove one integer
        System.out.println("Elements: "+Ts);
    }
}
Output:
>javac Test.java
>java Test
Elements: [1, 2, 3]
Is set empty: false
Is set empty: true
Size of the set: 3
Elements: [1, 3]

Hot to create a TreeSet from the list?
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
public class Test{
    public static void main(String a[]){
        List<Integer> Ali = new ArrayList<Integer>();
        Ali.add(1);
        Ali.add(2);
        Ali.add(3);
        Ali.add(4);
        System.out.println("Array List: "+Ali);
        //create a treeset with the list
        TreeSet<Integer> myset = new TreeSet<Integer>(Ali);
        System.out.println("Tree Set create using the List: "+myset);
    }
}
Output:
>javac Test.java
>java Test
Array List: [1, 2, 3, 4]

Tree Set create using the List: [1, 2, 3, 4]

How to implement sorting in TreeSet?
import java.util.Comparator;
import java.util.TreeSet;
public class Test{
    public static void main(String a[]){
        TreeSet<String> ts = new TreeSet<String>(new MyComp());
        ts.add("Java");
        ts.add("Hello");
        ts.add("leaner");
        System.out.println(ts);
    }
}
class MyComp implements Comparator<String>{
    @Override
    public int compare(String str1, String str2) {
        return str1.compareTo(str2);
    }
}
>javac Test.java
>java Test

[Hello, Java, leaner]

Differences between TreeSet, LinkedHashSet and HashSet:


HashSet
LinkedHashSet
TreeSet
General purpose collection
Follows insertion order
Sorting purpose
Implements Set
Implements Set
Implements Set
Doesn’t allow duplicates
Doesn’t allow duplicates
Doesn’t allow duplicates
Not Thread-Safe
Not Thread-Safe
Not Thread-Safe
Returns fail-fast iterator
Returns fail-fast iterator
Returns fail-fast iterator
Speed:fast
Speed:intermediate
Speed:slow due to sorting
Backed by HashMap
Backed by LinkedHashMap
Backed by TreeSet
Allows null
Allows null
Doesn’t allow null
Uses equals() for comparison
Uses equals() for comparison
Uses CompareTo() for comparison
Time complexity O(1)
Time complexity O(1)
Time complexity O(log(n))

No comments:

Post a Comment