cs205: engineering software?
(none)
20 September 2010

CS205 Notes 8 (4 September 2006)

cs205 Data Abstraction Notes
(Friday 8 September - Monday 11 September)

Upcoming Schedule

Data Abstraction

Data abstraction separates what you can do with data from how it is represented.

What are the advantages and disadvantages of using abstract data types?






What are the minimal operations a (useful) data abstraction must provide?






Specifying Data Abstractions

Is it reasonable for a datatype to have no mutators?



Is it reasonable for a datatype to have no creators?



Is it reasonable for a datatype to have no observers?

public class Set {
   OVERVIEW: A Set is a mutable, unbounded set of objects of
      type T.  A typical Set is {x_1, ..., x_n }.

    public Set()  
       EFFECTS: Initializes this to an empty set: { }.

    public boolean add(T el)
       MODIFIES: this
       EFFECTS: Adds el to the elements of this:
                   thispost = thispre U { el }
          Returns true iff el was not an element of thispre.

    public boolean contains(T el)
        EFFECTS:






    public void union(Set<T> t)







    

What missing operations are needed for an adequate Set datatype?





Is it necessary to provide union?

Implementing Data Abstractions

The most important decision in implementing a data abstraction, is selecting the concrete representation and understanding the mapping between that representation and the abstract values. Abstraction Function

The Abstraction Function maps a concrete state to an abstract state:

AF: CA
It is a function from concrete representation to the abstract notation introduced in overview specification.
   // AF (c) = { AFT (c.els[i]) | 0 <= i < c.els.size () }
Representation Invariant

The Representation Invariant expresses properties all legitimate objects of the ADT must satisfy. It is a function from concrete representation to boolean:

I: C → boolean

To check correctness we assume all objects passed in to a procedure satisfy the invariant and prove all objects satisfy the invariant before leaving the implementation code.

public class Set<T> {
   // OVERVIEW: A Set is a mutable, unbounded set of objects of type T.  
   //      A typical Set is {x_1, ..., x_n }.

   // Representation:
   private Vector<T> rep;

   // RepInvariant (c) = c.rep contains no duplicates && c.rep != null
   //                    && all elements of c.rep are of non-null 
If we instead used RepInvariant (c) = true which operations would be easier to implement correctly? Which would be harder?






Where can an implementer of a datatype assume the rep invariant is true?






Where must an implementer of a datatype ensure the rep invariant is true?

Graph

Here is the specification for a Graph datatype. It has some similarities to the DirectedGraph datatype from ps2, but some differences also.
public class Graph {
   // OVERVIEW: 
   //      A Graph is a mutable type that represents an undirected
   //      graph.  It consists of nodes that are named by Strings,
   //      and edges that connect a pair of nodes.
   //      A typical Graph is: < Nodes, Edges >
   //       where
   //         Nodes = { n1, n2, , nm }
   //       and 
   //         Edges = { {a_1, b_1}, ..., {a_n, b_n} }
   //         (note that the elements of Edges are unordered sets)

   // Creator
   public Graph () 
      // EFFECTS: Initializes this to a graph
      //      with no nodes or edges: < {}, {} >.

   // Mutators
   public void addNode (String name) throws DuplicateException
      // MODIFIES: this
      // EFFECTS: If name is in Nodes, throws DuplicateException.
      //    Otherwise, adds a node named name to this:
      //     this_post = < Nodes_pre U { name }, Edges_pre >

   public void addEdge (String fnode, String tnode) throws
      NoNodeException, DuplicateException
      // MODIFIES: this
      // EFFECTS: If s and t are not names of nodes in
      //    this, throws NoNodeException.  If there is already an edge
      //    between s and t, throws DuplicateEdgeException.
      //    Otherwise, adds an edge between s and t to this:
      //      thispost = < Nodespre, Edgespre U {fnode, tnode} >

   // Observers
   public boolean hasNode (String node)
      // EFFECTS: Returns true iff node is a node in this.

   Set getNeighbors (String node)
      // REQUIRES: node is a node in this
      // EFFECTS: Returns the set consisting of all nodes in this
      //      that are directly connected to node:
      //         { n | {node, n} is in this.edges }
}
  1. Select a representation for Graph. Consider carefully several different possible representations, and what their advantages and disadvantages will be.
  2. Determine the rep invariant and abstraction function
  3. Implement Graph (), addNode and hasHode
  4. Implement addEdge and getNeighbors