Java Software Structures: John Lewis & Joseph Chase CHAPTER 15: Sets and Maps Java Software Structures: Designing and Using Data Structures Third Edition John Lewis & Joseph Chase
Chapter Objectives Define set and map collections Use a set collection to solve a problem Examine an array implementation of a set Examine a linked implementation of a set Explore Java Collections API implementations of set and maps
A Set Collection Lets consider a collection based upon the idea of an algebraic set Such a set collection does not allow duplicates and groups elements without regard to their relationship to each other It's as if you threw them all in a box You can reach into a box and pull out an element, and are equally likely to get any one It is a nonlinear collection, but could be implemented with a linear data structure
The conceptual view of a set collection
The operations on a set collection
A SetADT /** * SetADT defines the interface to a set collection. * * @author Dr. Lewis * @author Dr. Chase * @version 1.0, 9/21/2008 */ package jss2; import java.util.Iterator; public interface SetADT<T> { * Adds one element to this set, ignoring duplicates. * @param element the element to be added to this set public void add (T element);
A SetADT (continued) /** * Removes and returns a random element from this set. * * @return a random element from this set */ public T removeRandom (); * Removes and returns the specified element from this set. * @param element the element to be removed from this list * @return the element just removed from this list public T remove (T element); * Returns the union of this set and the parameter * @param set the set to be unioned with this set * @return a set that is the union of this set and the parameter public SetADT<T> union (SetADT<T> set);
A SetADT (continued) /** * Returns true if this set contains the parameter * * @param target the element being sought in this set * @return true if this set contains the parameter */ public boolean contains (T target); * Returns true if this set and the parameter contain exactly * the same elements * @param set the set to be compared with this set * @return true if this set and the parameter contain exactly * the same elements public boolean equals (SetADT<T> set); * Returns true if this set contains no elements * @return true if this set contains no elements public boolean isEmpty();
A SetADT (continued) /** * Returns the number of elements in this set * @return the interger number of elements in this set */ public int size(); * Returns an iterator for the elements in this set * @return an iterator for the elements in this set public Iterator<T> iterator(); * Returns a string representation of this set * @return a string representation of this set public String toString(); }
UML description of the SetADT<T> interface
Using a Set: BINGO The game of BINGO can be used to demonstrate the use of a set collection Each player has a bingo card with numeric values associated with the letters B-I-N-G-O Letter/number combinations (on bingo balls) are picked at random, which the player marks on their card if possible The first player to get five squares in a row wins
A bingo card
BINGO A set is an appropriate collection for BINGO, allowing the caller to pick numbers at random We create an object of class BingoBall to represent one letter/number combination The main program creates the balls, stores them in a set, and draws them at random
The BingoBall class /** * BingoBall represents a ball used in a Bingo game. * * @author Dr. Lewis * @author Dr. Chase * @version 1.0, 9/21/2008 */ public class BingoBall { private char letter; private int number; * Sets up this Bingo ball with the specified number and the * appropriate letter. * @param num the number to be applied to the new bingo ball
The BingoBall class (continued) public BingoBall (int num) { number = num; if (num <= 15) letter = 'B'; else if (num <= 30) letter = 'I'; if (num <= 45) letter = 'N'; if (num <= 60) letter = 'G'; letter = 'O'; }
The BingoBall class (continued) /** * Returns a string representation of this bingo ball. * * @return a string representation of the bingo ball */ public String toString () { return (letter + " " + number); }
The Bingo class /** * Bingo demonstrates the use of a set collection. * @author Dr. Lewis * @author Dr. Chase * @version 1.0, 9/21/2008 */ import jss2.ArraySet; public class Bingo { * Creates all 75 Bingo balls and stores them in a set. Then * pulls several balls from the set at random and prints them. public static void main (String[] args) final int NUM_BALLS = 75, NUM_PULLS = 10; ArraySet<BingoBall> bingoSet = new ArraySet<BingoBall>(); BingoBall ball;
The Bingo class (continued) for (int num = 1; num <= NUM_BALLS; num++) { ball = new BingoBall (num); bingoSet.add (ball); } System.out.println ("Size: " + bingoSet.size()); System.out.println (); for (int num = 1; num <= NUM_PULLS; num++) ball = bingoSet.removeRandom(); System.out.println (ball);
UML description of the Bingo and BingoBall classes
Implementing a set with arrays The ArraySet class represents an array implementation of a set collection Set elements are kept contiguously at one end of the array An integer (count) represents: the number of elements in the set the next empty index in the array
An array implementation of a set
The ArraySet class /** * ArraySet represents an array implementation of a set. * * @author Dr. Lewis * @author Dr. Chase * @version 1.0, 9/21/2008 */ package jss2; import jss2.exceptions.*; import java.util.*; public class ArraySet<T> implements SetADT<T>, Iterable<T> { private static Random rand = new Random(); private final int DEFAULT_CAPACITY = 100; private final int NOT_FOUND = -1; private int count; // the current number of elements in the set private T[] contents;
The ArraySet class - constructors /** * Creates an empty set using the default capacity. */ public ArraySet() { count = 0; contents = (T[])(new Object[DEFAULT_CAPACITY]); } * Creates an empty set using the specified capacity. * * @param initialCapacity the initial capacity for the array set public ArraySet (int initialCapacity) contents = (T[])(new Object[initialCapacity]);
The ArraySet class - add /** * Adds the specified element to the set if it is not already * present. Expands the capacity of the set array if necessary. * * @param element the element to be added to the set array */ public void add (T element) { if (!(contains(element))) if (size() == contents.length) expandCapacity(); contents[count] = element; count++; }
The ArraySet class - addAll /** * Adds the contents of the parameter to this set. * * @param set the collection to be added to this set */ public void addAll (SetADT<T> set) { Iterator<T> scan = set.iterator(); while (scan.hasNext()) add (scan.next()); }
The ArraySet class - removeRandom /** * Removes a random element from the set and returns it. Throws * an EmptyCollectionException if the set is empty. * * @return a random element from the set * @throws EmptyCollectionException if an empty set exception occurs */ public T removeRandom() throws EmptyCollectionException { if (isEmpty()) throw new EmptyCollectionException("Stack"); int choice = rand.nextInt(count); T result = contents[choice]; contents[choice] = contents[count-1]; // fill the gap contents[count-1] = null; count--; return result; }
The ArraySet class - remove /** * Removes the specified element from the set and returns it. * Throws an EmptyCollectionException if the set is empty and a * NoSuchElementException if the target is not in the set. * * @param target the element being sought in the set * @return the element specified by the target * @throws EmptyCollectionException if an empty set exception occurs * @throws NoSuchElementException if a no such element exception occurs */ public T remove (T target) throws EmptyCollectionException, NoSuchElementException { int search = NOT_FOUND; if (isEmpty()) throw new EmptyCollectionException("Stack");
The ArraySet class – remove (cont.) for (int index=0; index < count && search == NOT_FOUND; index++) if (contents[index].equals(target)) search = index; if (search == NOT_FOUND) throw new NoSuchElementException(); T result = contents[search]; contents[search] = contents[count-1]; contents[count-1] = null; count--; return result; }
The ArraySet class – union /** * Returns a new set that is the union of this set and the * parameter. * * @param set the set that is to be unioned with this set * @return a new that that is the union of this set and * the parameter */ public SetADT<T> union (SetADT<T> set) { ArraySet<T> both = new ArraySet<T>(); for (int index = 0; index < count; index++) both.add (contents[index]); Iterator<T> scan = set.iterator(); while (scan.hasNext()) both.add (scan.next()); return both; }
The ArraySet class – contains /** * Returns true if this set contains the specified target * element. * * @param target the element being sought within this set * @return true if the set contains the target element */ public boolean contains (T target) { int search = NOT_FOUND; for (int index=0; index < count && search == NOT_FOUND; index++) if (contents[index].equals(target)) search = index; return (search != NOT_FOUND); }
The ArraySet class – equals /** * Returns true if this set contains exactly the same elements * as the parameter. * * @param set the set to be compared with this set * @return true if the parameter set and this set contain * exactly the same elements */ public boolean equals (SetADT<T> set) { boolean result = false; ArraySet<T> temp1 = new ArraySet<T>(); ArraySet<T> temp2 = new ArraySet<T>(); T obj; if (size() == set.size()) temp1.addAll(this); temp2.addAll(set);
The ArraySet class – equals (cont.) while (scan.hasNext()) { obj = scan.next(); if (temp1.contains(obj)) temp1.remove(obj); temp2.remove(obj); } result = (temp1.isEmpty() && temp2.isEmpty()); return result;
Complete UML description of the bingo system
A linked implementation of a set collection
The LinkedSet class /** * LinkedSet represents a linked implementation of a set. * * @author Dr. Chase * @author Dr. Lewis * @version 1.0, 9/21/2008 */ package jss2; import jss2.exceptions.*; import java.util.*; public class LinkedSet<T> implements SetADT<T>, Iterable<T> { private static Random rand = new Random(); private int count; // the current number of elements in the set private LinearNode<T> contents; * Creates an empty set. public LinkedSet() count = 0; contents = null; }
The LinkedSet class – add /** * Adds the specified element to this set if it is not already * present. * * @param element the element to be added to this set */ public void add (T element) { if (!(contains(element))) LinearNode<T> node = new LinearNode<T> (element); node.setNext(contents); contents = node; count++; }
The LinkedSet class – removeRandom /** * Removes and returns a random element from this set. Throws * an EmptySetException if the set contains no elements. * * @return a random element from this set * @throws EmptyCollectionException if an empty set exception occurs */ public T removeRandom() throws EmptyCollectionException { LinearNode<T> previous, current; T result = null; if (isEmpty()) throw new EmptyCollectionException("Stack"); int choice = rand.nextInt(count) + 1;
The LinkedSet class – removeRandom (continued) if (choice == 1) { result = contents.getElement(); contents = contents.getNext(); } else previous = contents; for (int skip=2; skip < choice; skip++) previous = previous.getNext(); current = previous.getNext(); result = current.getElement(); previous.setNext(current.getNext()); count--; return result;
The LinkedSet class – remove /** * Removes and returns the specified element from this set. * Throws an EmptySetException if the set is empty and a * NoSuchElemetnException if the target is not in the set. * * @param target the element being sought in this set * @return the element just removed from this set * @throws EmptyCollectionException if an empty set exception occurs * @throws NoSuchElementException if a no such element exception occurs */ public T remove (T target) throws EmptyCollectionException, NoSuchElementException { boolean found = false; LinearNode<T> previous, current; T result = null;
The LinkedSet class – remove (cont.) if (contents.getElement().equals(target)) { result = contents.getElement(); contents = contents.getNext(); } else previous = contents; current = contents.getNext(); for (int look=0; look < count && !found; look++) if (current.getElement().equals(target)) found = true; previous = current; current = current.getNext();
The LinkedSet class – remove (cont.) if (!found) throw new NoSuchElementException(); result = current.getElement(); previous.setNext(current.getNext()); } count--; return result;
Sets and Maps in the Java Collections API In Chapter 10, we discussed the TreeSet and TreeMap classes as well as the difference between a set and a map in Java In Chapter 14, we continued that discussion with the discussion of the various hashing implementations (Hashtable, HashMap, HashSet, IdentityHashMap, LinkedHashSet, LinkedHashMap, WeakHashMap) All of these are implementations of either the java.util.Set or java.util.Map interfaces Unlike our version which is designed to behave like an algebraic set, these Java implementations are simply generic collections