Data Structures for Java Data Structures for Java
William H. Ford William H. Ford William R. Topp William R. Topp
Chapter 20 Chapter 20
Ordered Set and Map Implementation Ordered Set and Map Implementation
Bret Ford
Implementing the Implementing the
TreeSet Class TreeSet Class
TreeSet class is actually the STree class TreeSet class is actually the STree class that implements the Set and OrderedSet that implements the Set and OrderedSet
interfaces.
interfaces.
Private static inner class STNode objects store Private static inner class STNode objects store data.
data.
OrderedSet Interface Hierarchy
OrderedSet Interface Hierarchy
TreeSet Class TreeSet Class
public class TreeSet<T> implements OrderedSet<T>
{
// reference to root of a search tree that is // the underlying storage structure for a
// TreeSet collection private STNode<T> root;
// number of elements in the tree private int setSize;
// increases whenever the tree changes;
// used by an iterator to verify that it // is in a consistent state
private int modCount;
...
TreeSet Class (concluded) TreeSet Class (concluded)
// inner class that provides for // iterator operations
private class IteratorImpl implements Iterator<T>
{
...
}
// static inner class that defines STNode // objects which are the building blocks // of the binary search tree
private static class STNode<T>
{
...
} }
TreeMap Implementation TreeMap Implementation
Overview Overview
The TreeMap class implements the Map The TreeMap class implements the Map
interface which defines methods like get(), interface which defines methods like get(),
put(), and remove() that access and put(), and remove() that access and
update elements in a map collection.
update elements in a map collection.
The Map interface specifies the interface The Map interface specifies the interface
Map.Entry as an inner interface that defines Map.Entry as an inner interface that defines
the structure of the key value pairs that are ‑ the structure of the key value pairs that are ‑
inserted into a map.
inserted into a map.
TreeMap Implementation TreeMap Implementation
Overview (continued) Overview (continued)
In an entry set, a programmer can use a Map.Entry reference to access the key and value with the methods getKey() and
getValue() and can update the value
component using setValue(). No update to
the key component is available since the
operation could destroy the tree ordering
of the map.
TreeMap Implementation TreeMap Implementation
Overview (continued) Overview (continued)
The OrderedMap interface defines methods that return minimum and maximum
elements. The method firstKey() returns
the first (least) key in the ordered map,
and the method lastKey() returns the last
(greatest) key in the map.
TreeMap Implementation TreeMap Implementation
Overview (continued) Overview (continued)
The UML diagram shows the relationship between the Map, Map.Entry and
OrderedMap interfaces.
TreeMap Implementation TreeMap Implementation
Overview (continued) Overview (continued)
Implement a TreeMap as a binary search tree of Entry nodes, where Entry is a private static inner class. Each node has a key-value pair
and references to its children and parent.
TreeMap Implementation TreeMap Implementation
Overview (concluded) Overview (concluded)
The Entry objects in the search tree are ordered by the key.
The figure illustrates a TreeMap with solid lines
connecting a node to its children and a dotted
line connecting a node to its parent.
Entry as an Inner-Class Entry as an Inner-Class
Within TreeMap Within TreeMap
public class TreeMap<K,V> implements OrderedMap<K,V>
{
. . .
// declares a binary search tree node object private static class Entry<K,V>
implements Map.Entry<K,V>
{
// node data K key;
V value;
Entry as an Inner-Class Entry as an Inner-Class
Within TreeMap Within TreeMap
(continued) (continued)
// constructor that initializes the value // and parent fields and sets the link // fields left and right to null
public Entry(K key, V value, Entry<K,V> parent) {
this.key = key;
this.value = value;
left = null;
right = null;
this.parent = parent;
}
Entry as an Inner-Class Entry as an Inner-Class
Within TreeMap Within TreeMap
(continued) (continued)
// returns the key public K getKey() { return key; }
// returns the value associated with the key public V getValue()
{ return value; }
Entry as an Inner-Class Entry as an Inner-Class
Within TreeMap Within TreeMap
(concluded) (concluded)
// updates the value currently associated // with the key with a new one and returns // the original value
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
// used by TreeMap toString() to list the // pair as "key=value"
public String toString()
{ return key + "=" + value; }
TreeMap Class Design TreeMap Class Design
The TreeMap class builds a binary search The TreeMap class builds a binary search tree of Entry objects.
tree of Entry objects.
Variables Variables
The private instance variable root is a reference to The private instance variable root is a reference to an Entry node that defines the search tree.
an Entry node that defines the search tree.
Two integer variables mapSize and modCount Two integer variables mapSize and modCount
maintain the size of the collection and the number maintain the size of the collection and the number of tree modifications (insertions and deletions).
of tree modifications (insertions and deletions).
TreeMap Class Design TreeMap Class Design
(continued) (continued)
The class constructor creates an empty The class constructor creates an empty
map and toString() displays the entries as map and toString() displays the entries as
comma-separated elements enclosed in comma-separated elements enclosed in
braces ("{", "}"). Each element has the braces ("{", "}"). Each element has the
form "key=value".
form "key=value".
The other methods implement The other methods implement
OrderedMap interface operations.
OrderedMap interface operations.
TreeMap Class Design TreeMap Class Design
(continued) (continued)
The figure shows a UML diagram The figure shows a UML diagram
illustrating the design of the TreeMap illustrating the design of the TreeMap
class. The inner classes IteratorImpl, class. The inner classes IteratorImpl,
KeyIterator, and EntryIterator are involved KeyIterator, and EntryIterator are involved
with the collection views of a map.
with the collection views of a map.
TreeMap Class – Basic TreeMap Class – Basic
Class Structure Class Structure
public class TreeMap<K,V> implements OrderedMap<K,V>
{
// root defines the search tree of Entry nodes private Entry<K,V> root;
// size of the map private int mapSize;
// modCount maintains a record of changes // to the map for iterators
private int modCount;
TreeMap Class – Basic TreeMap Class – Basic
Class Structure Class Structure
(concluded) (concluded)
// constructor creates an empty map public TreeMap()
{
root = null;
mapSize = 0;
modCount = 0;
}
< Methods defined by the OrderedMap interface >
. . .
Key Access to an Entry:
Key Access to an Entry:
getEntry() getEntry()
Map methods such as get(), Map methods such as get(),
containsKey(), and remove() use a key containsKey(), and remove() use a key
argument to access an entry in the map.
argument to access an entry in the map.
The private method getEntry() takes a key The private method getEntry() takes a key and searches the tree for a pair with the and searches the tree for a pair with the
specified key. It returns a reference to the specified key. It returns a reference to the
key-value pair in the tree or null of it failed to key-value pair in the tree or null of it failed to
locate an entry with the key.
locate an entry with the key.
Key Access to an Entry:
Key Access to an Entry:
getEntry() (continued) getEntry() (continued)
// iteratively traverse a path from the root // to the entry key; return a reference to the
// node containing key or null if the search fails private Entry<K,V> getEntry(K key)
{
// scan variable entry references the current // node in the traversal
Entry<K,V> entry = root;
int orderValue;
// terminate on an empty subtree while(entry != null)
{
Key Access to an Entry:
Key Access to an Entry:
getEntry() (concluded) getEntry() (concluded)
// if a match occurs, return true;
// otherwise, go left or go right // following search tree order if (orderValue == 0)
return entry;
else if (orderValue < 0) entry = entry.left;
else
entry = entry.right;
}
return null;
}
Key Access to an Entry:
Key Access to an Entry:
containsKey() containsKey()
The method containsKey() indicates The method containsKey() indicates
whether an entry with the specified key is whether an entry with the specified key is
in the map. Its implementation is a direct in the map. Its implementation is a direct
application of getEntry().
application of getEntry().
Key Access to an Entry:
Key Access to an Entry:
containsKey() (concluded) containsKey() (concluded)
// returns true if this map contains an entry // with the specified key
public boolean containsKey(Object key) {
return getEntry((K)key) != null;
}
Key Access to an Entry: get() Key Access to an Entry: get()
Access to the value component of a key- Access to the value component of a key- value pair is provided by the method
value pair is provided by the method get().
get().
After calling getEntry() to locate the entry, the After calling getEntry() to locate the entry, the method returns null or the value field
method returns null or the value field
depending on whether the entry is in the
depending on whether the entry is in the
map. map.
Key Access to an Entry: get() Key Access to an Entry: get()
(concluded) (concluded)
// returns the value correponding to key public V get(K key)
{
Entry<K,V> p = getEntry(key);
if (p == null) return null;
else
return p.getValue();
}
Updating an Entry: put() Updating an Entry: put()
The put() operation with arguments for The put() operation with arguments for the key and the value either updates the the key and the value either updates the
value field for an existing entry or adds a value field for an existing entry or adds a
new entry.
new entry.
Start at the root and search down a path Start at the root and search down a path
using search tree ordering. If a match occurs, using search tree ordering. If a match occurs,
use setValue() to update the value field in the use setValue() to update the value field in the
matching entry.
matching entry.
Otherwise,create an Entry object with the Otherwise,create an Entry object with the
Updating an Entry: put() Updating an Entry: put()
(continued) (continued)
// associates the specified value with the // specified key in this map; returns the // previous value associated with the key, // or null if there was no mapping for key public V put(K key, V value)
{
// entry is current node in traversal, parent // the previous node
Entry<K,V> entry = root, parent = null, newNode;
int orderValue = 0;
// terminate on an empty subtree while(entry != null)
{
// update the parent reference parent = entry;
// compare key to the current node key
orderValue = ((Comparable<K>)key).compareTo(
Updating an Entry: put() Updating an Entry: put()
(continued) (continued)
// if a match occurs, replace the value // in entry and return the previous value;
// otherwise, go left or go right following // search tree order
if (orderValue == 0)
// return; put() is an update return entry.setValue(value);
else if (orderValue < 0) entry = entry.left;
else
entry = entry.right;
}
Updating an Entry: put() Updating an Entry: put()
(concluded) (concluded)
if (parent == null)
// this is the first node added; make it root root = newNode;
else if (orderValue < 0)
// attach newNode as the left child of parent parent.left = newNode;
else
// attach newNode as the right child of parent parent.right = newNode;
// increment the tree size and modCount mapSize++;
modCount++;
// the return is the value of a matching entry;
// returning null indicates we added a new pair // to the tree
Removing an Entry: remove() Removing an Entry: remove()
Use getEntry() to determine if there is a Use getEntry() to determine if there is a key value pair in the map with the ‑
key value pair in the map with the ‑ specified key.
specified key.
If there is, the private method removeNode() If there is, the private method removeNode() takes a reference to the node and deletes it takes a reference to the node and deletes it
from the tree. The method removeNode() from the tree. The method removeNode()
uses the deletion algorithm for a binary uses the deletion algorithm for a binary
search tree.
search tree.
Removing an Entry: remove() Removing an Entry: remove()
(concluded) (concluded)
// removes the entry containing key from // this map if present
public V remove(Object key) {
// search tree for key
Entry<K,V> dNode = getEntry((K)key);
if (dNode == null) return null;
V returnObj = dNode.getValue();
removeNode(dNode);
mapSize--;
modCount++;
A Collection View A Collection View
A collection view object does not have its A collection view object does not have its own data. It uses the data in the
own data. It uses the data in the backing backing collection
collection . .
A view object has operations that are tied to A view object has operations that are tied to operations in the backing collection. In the operations in the backing collection. In the
case of a keySet collection view for a map, the case of a keySet collection view for a map, the operations implement the Set interface but the operations implement the Set interface but the add() operation is disallowed. The data are the add() operation is disallowed. The data are the
keys of the entries in the backing map.
keys of the entries in the backing map.
StoreOneTwo Class StoreOneTwo Class
Class StoreOneTwo Class StoreOneTwo
Variables one and two that hold integer Variables one and two that hold integer values.
values.
A constructor that initializes the values. A constructor that initializes the values.
toString() that provides a representation of toString() that provides a representation of the object in the form "one=two".
the object in the form "one=two".
Method setOneTwo() that allows the Method setOneTwo() that allows the programmer to update the variables.
programmer to update the variables.
View Interface View Interface
Associated with the class StoreOneTwo Associated with the class StoreOneTwo create an interface called View defining create an interface called View defining
methods get() and set() that may be used methods get() and set() that may be used
by a View object to access and update a by a View object to access and update a
field in the backing object.
field in the backing object.
View interface (concluded) View interface (concluded)
// an object that implements View has // methods to access and update a data // item in a backing object
public interface View {
int get();
void set(int value);
}
StoreOneTwo Class StoreOneTwo Class
(continued) (continued)
The StoreOneTwo class defines the The StoreOneTwo class defines the
method viewOne() which returns a View method viewOne() which returns a View
object that is associated with field one in a object that is associated with field one in a
StoreOneTwo object.
StoreOneTwo object.
StoreOneTwo Class StoreOneTwo Class
Declaration Declaration
public class StoreOneTwo {
// object has two integer fields private int one, two;
// constructor; initialize data fields public StoreOneTwo(int one, int two) {
this.one = one;
this.two = two;
}
// return a representation of the object public String toString()
{ return one + "=" + two; }
StoreOneTwo Class StoreOneTwo Class
Declaration (concluded) Declaration (concluded)
// update the data fields
public void setOneTwo(int one, int two) {
this.one = one;
this.two = two;
}
// object that is returned by viewOne() private View viewObj = null;
// method returns a View object // associated with field one
Example using viewOne() Example using viewOne()
// create object and display its current values StoreOneTwo st = new StoreOneTwo(5, 35);
// use the View object to access the first field in st View v = st.view();
Example using viewOne() Example using viewOne()
(concluded) (concluded)
System.out.println("Initial object st: " + st);
System.out.println("Value viewed from st = " + v.get());
// use view object v to update the first field in st v.set(25);
System.out.println("Updated object st: " + st);
// use setOneTwo() to update the object directly the // display the view of the object using v.get()
st.setOneTwo(3, 7);
System.out.println("Value viewed from updated st: " + v.get());
Output:
Initial object st: 5=35
Implementing a View Implementing a View
In the StoreOneTwo class, the method In the StoreOneTwo class, the method viewOne() returns an object that
viewOne() returns an object that
implements the View interface. The object implements the View interface. The object
does not have its own data; rather, it does not have its own data; rather, it
relies on access to the variable one in a relies on access to the variable one in a
StoreOneTwo object.
StoreOneTwo object.
Implementing a View Implementing a View
(continued) (continued)
A view is usually implemented using an A view is usually implemented using an anonymous inner class
anonymous inner class . Such a class does . Such a class does not have a name. An anonymous inner
not have a name. An anonymous inner
class combines the declaration of an inner class combines the declaration of an inner
class with the creation of an instance of the class with the creation of an instance of the
class in one step, e.g.
class in one step, e.g.
// object that is returned by viewOne() private View viewObj = null;
...
Implementing a View Implementing a View
(continued) (continued)
// object that is returned by viewOne() private View viewObj = null;
// method returns a View object that // accesses the StoreOneTwo field one public View viewOne()
{
// we only generate one instance of the // anonymous inner class object
if (viewObj == null) viewObj = new View() {
// methods in the View interface public int get()
{ return one; }
public void set(int value)
Implementing a View Implementing a View
(concluded) (concluded)
// return the object created by // the method viewOne()
return viewObj;
}
The keySet Collection View The keySet Collection View
The TreeMap class implements its keySet The TreeMap class implements its keySet and entrySet views by returning an
and entrySet views by returning an anonymous inner class object that anonymous inner class object that
implements the Set interface and uses the implements the Set interface and uses the
map data.
map data.
keySet() Outline keySet() Outline
private Set<K> keySet = null;
public Set<K> keySet() {
if (keySet == null) {
keySet = new Set<K>() {
public Iterator<K> iterator() { . . . }
public int size() { . . . }
public boolean contains(Object item)
keySet() Outline (concluded) keySet() Outline (concluded)
public void clear() { . . . }
public boolean isEmpty() { . . . }
public boolean add(K key) {
throw new UnsupportedOperationException();
} };
}
return keySet;
}
Implementation of keySet() Implementation of keySet()
methods methods
The Set methods size(), isEmpty(), and The Set methods size(), isEmpty(), and
clear() have implementations that use the clear() have implementations that use the
corresponding TreeMap methods.
corresponding TreeMap methods.
To reference "this" for the enclosing class, To reference "this" for the enclosing class, preface it by the name of the enclosing class preface it by the name of the enclosing class
followed by the "." operator. For instance, followed by the "." operator. For instance,
TreeMap.this.size() refers to the method
TreeMap.this.size() refers to the method
keySet Collection keySet Collection
view size() view size()
// access size in the backing map public int size()
{ return TreeMap.this.size(); }
keySet Collection keySet Collection
view contains() view contains()
// use containsKey() to check if the entry // with item as its key is in the map
public boolean contains(Object item) { return containsKey(item); }
keySet Collection keySet Collection
view add() view add()
The Set method add() must be The Set method add() must be
implemented. The object would become a implemented. The object would become a
key without any associated value. Throw an key without any associated value. Throw an
UnsupportedOperationException which has UnsupportedOperationException which has
the effect of making the operation invalid.
the effect of making the operation invalid.
public boolean add(K key) {
throw new UnsupportedOperationException();
}
TreeMap Iterators TreeMap Iterators
The keySet and the entrySet collection views The keySet and the entrySet collection views
provide an iterator that scans the keys in the map.
provide an iterator that scans the keys in the map.
In the implementation of keySet(), the method In the implementation of keySet(), the method
iterator() returns an Iterator object of type KeyIterator.
iterator() returns an Iterator object of type KeyIterator.
In the implementation of entrySet(), the return Iterator In the implementation of entrySet(), the return Iterator object is of type EntryIterator.
object is of type EntryIterator.
Both of these Iterator classes must implement next(), Both of these Iterator classes must implement next(), hasNext(), and remove().
hasNext(), and remove().
TreeMap Iterators (continued) TreeMap Iterators (continued)
Simply the task by creating a generic class Simply the task by creating a generic class IteratorImpl<T> that sequences through IteratorImpl<T> that sequences through
the key value pairs in the map and ‑ the key value pairs in the map and ‑
implements all the iterator methods implements all the iterator methods
except next().
except next().
The inner class KeyIterator is a subclass of The inner class KeyIterator is a subclass of the inner class IteratorImpl with generic type the inner class IteratorImpl with generic type
K. It adds an implementation for next() that K. It adds an implementation for next() that
returns the next key in the map.
returns the next key in the map.
TreeMap Iterators TreeMap Iterators
(continued) (continued)
private class KeyIterator extends IteratorImpl<K>
{
public K next() { . . . }
}
TreeMap Iterators TreeMap Iterators
(concluded) (concluded)
The inner class EntryIterator is a subclass The inner class EntryIterator is a subclass of the inner class IteratorImpl with generic of the inner class IteratorImpl with generic
type Map.Entry<K,V>. This class adds an type Map.Entry<K,V>. This class adds an
implementation for next() that returns the implementation for next() that returns the
next key-value pair (Entry) in the map next key-value pair (Entry) in the map
private class EntryIterator extends IteratorImpl<Map.Entry<K,V>>
{
public K next() { . . . }
}