Estructura de Datos : Juegos ( Sets )


Definiciones

Un juego representa un grupo de objetos, conocidos como sus elementos. Las juegos no permiten elementos duplicados y los mismos no están ordenados. Los elementos de un juego no son accedidos a través de un índice. Por el contrario su única forma de recuperación es uno a uno, secuencialmente.

En ingles set significa juego, surtido, coleccion, serie, grupo o clase.


Representaciones

Representación Secuencial


                                +--------------+
                                |   Iterador   |
                                |              |
                                |              |
     *--------*     *--------*  |  *--------*  |  *--------*     *--------*     *--------*     *--------*     *--------*     *--------*
     |        |     |        |  |  |        |  |  |        |     |        |     |        |     |        |     |        |     |        |
     |        |     |        |  |  |Elemento|  |  |        |     |        |     |        |     |        |     |        |     |        |
     |        |     |        |  X  |        |  V  |        |     |        |     |        |     |        |     |        |     |        |
     |        |     |        |     |Devuelto|     |        |     |        |     |        |     |        |     |        |     |        |
     |        |     |        |     |        |     |        |     |        |     |        |     |        |     |        |     |        |
     *--------*     *--------*     *--------*     *--------*     *--------*     *--------*     *--------*     *--------*     *--------*

      Elemento       Elemento       Elemento       Elemento       Elemento       Elemento       Elemento       Elemento       Elemento

Representación lineal


                 Elemento HH    Elemento CC    Elemento FF    Elemento CC    Elemento FF    Elemento BB    Elemento ZZ    Elemento HH
                   adicion        adicion        adicion      eliminacion      adicion        adicion        adicion      eliminacion

 *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*
 |           |  |Elemento HH|  |Elemento HH|  |Elemento HH|  |Elemento HH|  |Elemento HH|  |Elemento HH|  |Elemento HH|  |Elemento FF|
 *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*
 |           |  |           |  |Elemento CC|  |Elemento CC|  |Elemento FF|  |Elemento FF|  |Elemento FF|  |Elemento FF|  |Elemento BB|
 *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*
 |           |  |           |  |           |  |Elemento FF|  |           |  |           |  |Elemento BB|  |Elemento BB|  |Elemento ZZ|
 *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*
 |           |  |           |  |           |  |           |  |           |  |           |  |           |  |Elemento ZZ|  |           |
 *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*
 |           |  |           |  |           |  |           |  |           |  |           |  |           |  |           |  |           |
 *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*
 |           |  |           |  |           |  |           |  |           |  |           |  |           |  |           |  |           |
 *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*
 |           |  |           |  |           |  |           |  |           |  |           |  |           |  |           |  |           |
 *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*
 |           |  |           |  |           |  |           |  |           |  |           |  |           |  |           |  |           |
 *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*  *-----------*

   Tiempo t1      Tiempo t2      Tiempo t3      Tiempo t4      Tiempo t5      Tiempo t6      Tiempo t7      Tiempo t8      Tiempo t9


Interfases

Funciones Primitivas


        int     create()
        boolean add(int c, Object obj)
        void    begin(int c)
        Object  next(int c)
        boolean hasNext(int c)
        void    remove(int c)

El método create crea una Juego y retorna su identificador.

El método add adiciona un objeto al Juego y retorna true si la Juego cambio en virtud de la adición, de lo contrario retorna false, indicando que la Juego no ha cambiado. Por ejemplo, si se trata de adicionar un objeto que ya esta presente en el Juego la adición es rechazada, ya que no se aceptan duplicados.

El método begin ubica el iterador al comienzo de la Juego.

El método next recupera el siguiente objeto del Juego. Invocando repetidamente este método se visitan todos los objetos del Juego, uno a uno.

El método hasNext retorna true si existen más objetos en el Juego y retorna false en caso contrario. Siempre, antes de invocar la recuperación del siguiente objeto, debe consultarse si existen más objetos en el Juego.

El método remove elimina del Juego el último objeto recuperado.

Funciones Secundarias


        int      size(int c)
        boolean  isEmpty(int c)
        boolean  contains(int c, Object obj)
        boolean  containsAll(int c, Juego c)
        boolean  equals(int c, Object other)
        boolean  addAll(int c, Juego from)
        boolean  remove(int c, Object obj)
        boolean  removeAll(int c, Juego c)
        void     clear(int c)
        boolean  retainAll(int c, Juego c)
        Object[] toArray(int c)

El método size retorna el número de elementos actualmente almacenados en el Juego.

El método isEmpty retorna true si no existen elementos en el Juego.

El método contains retorna true si el Juego contiene un objeto igual a obj.

El método containsAll retorna true si el Juego contiene todos los objeto del Juego other.

El método addAll retorna true si el Juego ha cambiado por la adición de todos los objetos del Juego other.

El método removeAll retorna true si el Juego ha cambiado por la eliminación de todos los objetos del Juego other.

El método clear elimina todos los objetos del Juego.

El método retainAll retorna true si el Juego ha cambiado por la eliminación de todos los objetos no iguales del Juego other.

El método toArray retorna un Arreglo formado por los objetos del Juego.


Operaciones masivas con conjuntos

Las operaciones definidas en Juegos son utilies para ejecutar operaciones del algebra de conjuntos. Veamos los siguientes ejemplos.

      S1
     *-----------------------*
     |                       |
     |                S2     |                           S2 es un subset de S1 si
     |    *-------------*    |
     |    |             |    |
     |    |             |    |
     |    |             |    |
     |    *-------------*    |                              s1.containsAll(s2)
     |                       |
     *-----------------------*





      S1
     *-----------------------*
     |///////////////////////|
     |///////////////////////|       S2                      union de S1 y S2
     |///////////////////*-------------*
     |///////////////////|/////////////|
     |///////////////////|/////////////|
     |///////////////////|/////////////|
     |///////////////////*-------------*                       s1.addAll(s2)
     |///////////////////////|
     *-----------------------*





      S1
     *-----------------------*
     |                       |
     |                       |       S2                   interseccion de S1 y S2
     |                   *-------------*
     |                   |////         |
     |                   |////         |
     |                   |////         |
     |                   *-------------*                     s1.retainAll(s2)
     |                       |
     *-----------------------*





      S1
     *-----------------------*
     |///////////////////////|
     |///////////////////////|       S2                    diferencia de S1 y S2
     |///////////////////*-------------*
     |///////////////////|             |
     |///////////////////|             |
     |///////////////////|             |
     |///////////////////*-------------*                      s1.removeAll(s2)
     |///////////////////////|
     *-----------------------*





      S1
     *-----------------------*
     |                       |
     |                       |       S2                    diferencia de S2 y S1
     |                   *-------------*
     |                   |    /////////|
     |                   |    /////////|
     |                   |    /////////|
     |                   *-------------*                      s2.removeAll(s1)
     |                       |
     *-----------------------*


Clases e Interfases

                                                                         .........................
                                                                         .                       .
                                                                         .                       .
                                                                         .                       .
                                                                         .                       .
                                                                         .       Collection      .
                                                                         .                       .
                                                                         .                       .
                                                                         .                       .
                                                                         .........................
                                                                                     .
                                                                                     .
                                                                                     .
                                                                                     .
                                                                         .........................
                                                                         .                       .
                 .........................................................                       .
                 .                                                       .                       .
                 .                                                       .                       .
                 .                                                       .          Set          .
                 .                                                       .                       .
                 .                            ............................                       .
                 .                            .                          .                       .
                 .                            .                          .........................
                 .                            .
                 .                            .
                 .                            .
                 .                            .
     *-----------------------*    *-----------------------*
     |                       |    |                       |
     |                       |    |                       |
     |                       |    |                       |
     |                       |    |                       |
     |       HashSet         |    |        TreeSet        |
     |                       |    |                       |
     |                       |    |                       |
     |                       |    |                       |
     *-----------------------*    *-----------------------*


Lecturas complementarias

A Set is a Collection that cannot contain duplicate elements. Set models the mathematical set abstraction. The Set interface extends Collection and contains no methods other than those inherited from Collection. It adds the restriction that duplicate elements are prohibited. Set also adds a stronger contract on the behavior of the equals and hashCode operations, allowing Set objects with different implementation types to be compared meaningfully. Two Set objects are equal if they contain the same elements.

The Set interface is shown below:

public interface Set {
    // Basic Operations
    int size();
    boolean isEmpty();
    boolean contains(Object element);
    boolean add(Object element);    // Optional
    boolean remove(Object element); // Optional
    Iterator iterator();

    // Bulk Operations
    boolean containsAll(Collection c);
    boolean addAll(Collection c);    // Optional
    boolean removeAll(Collection c); // Optional
    boolean retainAll(Collection c); // Optional
    void clear();                    // Optional

    // Array Operations
    Object[] toArray();
    Object[] toArray(Object a[]);
}
The JDK contains two general-purpose Set implementations. HashSet , which stores its elements in a hash table, is the best-performing implementation. TreeSet , which stores its elements in a red-black tree, guarantees the order of iteration.

Here's a simple but useful Set idiom. Suppose you have a Collection, c, and you want to create another Collection containing the same elements, but with all duplicates eliminated. The following one-liner does the trick:

Collection noDups = new HashSet(c);
It works by creating a Set (which, by definition, cannot contain duplicates) initially containing all the elements in c. It uses the "standard Collection constructor" described in the Collection interface lesson.

Basic Operations

The size operation returns the number of elements in the Set (its cardinality). The isEmpty method does exactly what you think it does. The add method adds the specified element to the Set if it's not already present, and returns a boolean indicating whether the element was added. Similarly, the remove method removes the specified element from the Set if it's present, and returns a boolean indicating whether the element was present. The iterator method returns an Iterator over the Set.

Here's a little program that takes the words in its argument list and prints out any duplicate words, the number of distinct words, and a list of the words with duplicates eliminated:

import java.util.*;

public class FindDups {
    public static void main(String args[]) {
        Set s = new HashSet();
        for (int i=0; i<args.length; i++)
            if (!s.add(args[i]))
                System.out.println("Duplicate detected: "+args[i]);

        System.out.println(s.size()+" distinct words detected: "+s);
    }
}
Now let's run the program:
% java FindDups i came i saw i left

Duplicate detected: i
Duplicate detected: i
4 distinct words detected: [came, left, saw, i]
Note that the example code always refers to the collection by its interface type (Set), rather than by its implementation type (HashSet). This is a strongly recommended programming practice, as it gives you the flexibility to change implementations merely by changing the constructor. If the variables used to store a collection, or the parameters used to pass it around, are declared to be of the collection's implementation type rather than its interface type, then all such variables and parameters must be changed to change the collection's implementation type. Furthermore, there's no guarantee that the resulting program will work; if the program uses any non-standard operations that are present in the original implementation type but not the new one, the program will fail. Referring to collections only by their interface keeps you honest, in the sense that it prevents you from using any non-standard operations.

The implementation type of the Set in the example above is HashSet, which makes no guarantees as to the order of the elements in the Set. If you want the program to print the word list in alphabetical order, all you have to do is to change the set's implementation type from HashSet to TreeSet. Making this trivial one-line change causes the command line in the previous example to generate the following output:

% java FindDups i came i saw i left

Duplicate word detected: i
Duplicate word detected: i
4 distinct words detected: [came, i, left, saw]

Bulk Operations

The bulk operations are particularly well suited to Sets: they perform standard set-algebraic operations. Suppose s1 and s2 are Sets. Here's what the bulk operations do: To calculate the union, intersection, or set difference of two sets non-destructively (without modifying either set), the caller must copy one set before calling the appropriate bulk operation. The resulting idioms are shown below:
Set union = new HashSet(s1);
union.addAll(s2);

Set intersection = new HashSet(s1);
intersection.retainAll(s2);

Set difference = new HashSet(s1);
difference.removeAll(s2);
The implementation type of the result Set in the above idioms is HashSet, which is, as mentioned above, the best all-around Set implementation in the JDK. However, any general-purpose Set implementation could be substituted.

Let's revisit the FindDups example program above. Suppose you want to know which words in the argument list occur only once and which occur more than once, but you do not want any duplicates printed out repeatedly. This effect can be achieved by generating two sets, one containing every word in the argument list, and the other containing only the duplicates. The words that occur only once are the set difference of these two sets, which we know how to compute. Here's how the resulting program looks:

import java.util.*;

public class FindDups2 {
    public static void main(String args[]) {
        Set uniques = new HashSet();
        Set dups = new HashSet();

        for (int i=0; i<args.length; i++)
            if (!uniques.add(args[i]))
                dups.add(args[i]);

        uniques.removeAll(dups);  // Destructive set-difference

        System.out.println("Unique words:    " + uniques);
        System.out.println("Duplicate words: " + dups);
    }
}
Now let's run the revised program with the same same argument list we used before:
% java FindDups2 i came i saw i left

Unique words:    [came, left, saw]
Duplicate words: [i]
A less common set-algebraic operation is the symmetric set difference: the set of elements contained in either of two specified sets, but not contained in both of them. The following code calculates the symmetric set difference of two sets non-destructively:
Set symmetricDiff = new HashSet(s1);
symmetricDiff.addAll(s2);
Set tmp = new HashSet(s1);
tmp.retainAll(s2);
symmetricDiff.removeAll(tmp);

Array Operations

The array operations don't do anything special for Sets beyond what they do for any other Collection. They are described in the interface lesson.