Lecture 06: Relationships, Sets, and Running Times

Overview

  1. Relationships Between ADTs
    • Lists
    • Deques
    • Queues
    • Stacks
  2. The Set ADT
  3. Implementing Sets
  4. Running Time Assumptions

Relationships Between ADTs

Other ADTs

  • List
  • Deque
  • Stack
  • Queue

Simulating Operations

Question. Given a List, how can you simulate a Deque?

  • addFirst?
  • addLast?
  • removeFirst?

You’ve Already Seen This!

public class ASLDeque<E> implements SimpleDeque<E> {
    private SimpleList<E> list = new ArraySimpleList<E>();
	
    public int size() { return list.size(); }

    public boolean isEmpty() { return list.isEmpty(); }

    public void addFirst(E x) { list.add(0, x); }

    public E removeFirst() { return list.remove(0); }

    public E peekFirst() { return list.get(0); }

    public void addLast(E x) { list.add(list.size(), x); }

    public E removeLast() { return list.remove(list.size() - 1); }

    public E peekLast() { return list.get(list.size() - 1); }
}

Question

If we can always use a List, why would we ever want just a stack/queue/deque?

Designing for Efficency

Use the simplest ADTs that provides the required functionality to solve a problem

  • a straightforward implementation of a simple ADT is often more efficient than a sophisticated implementation of a more general ADT

See, e.g., Assignments 2 and 3

Sets

Sets

A set is a collection of unique elements

  • any element appears only once in the set

  • no order (index) associated with elements

Sets of numbers:

The Set ADT

Basic Operations:

  • determine size of set (number of distinct elements)
  • add an element to the set, if not already present
  • remove an element from set if present
  • find and return an element in set, if present

Set Example

Example \(\texttt{set} = \{2, 3, 4, 7, 11\}\)

  • set.add(3)
  • set.add(5)
  • set.remove(4)
  • set.find(7)
  • set.find(8)

SimpleUSet Interface

public interface SimpleUSet<E> {
    int size();

    boolean isEmpty();

    boolean add(E x);

    E remove(E x);

    E find(E x);
}

Question 1

How can we implement a SimpleUSet using a SimpleList?

public interface SimpleList<E> {
    int size();
    boolean isEmpty();
    E get(int i);
    void set(int i, E x);
    void add(int i, E x);
    E remove(int i);
}
public interface SimpleUSet<E> {
    int size();
    boolean isEmpty();
    boolean add(E x);
    E remove(E x);
    E find(E x);
}

How to Add to a Set?

public class ListSimpleUSet<E> implements SimpleUSet<E> {
    private SimpleList<E> list;
	
    ...
	
    public boolean add(E x) {
	    ...
    }
}

How to Remove?

public class ListSimpleUSet<E> implements SimpleUSet<E> {
    private SimpleList<E> list;
	
    ...
	
    public E remove(E x) {
	    ...
    }
}

How to Find?

public class ListSimpleYSet<E> implements SimpleUSet<E> {
    private SimpleList<E> list;
	
    ...
	
    public E find(E x) {
	    ...
    }
}

Question 2

Which SimpleList implementation would be more efficient to use in ListSimpleUSet?

  • ArraySimpleList
  • LinkedSimpleList

Will there be a big difference in performance?

Consider add operation

  • What SimpleList operations does add use?
  • How many such operations does operations does add require?
  • How efficient is each operation for…
    • ArraySimpleList?
    • LinkedSimpleList?

Testing our ListSimpleUSet

Make ListSimpleUSet.java

  • constructor allows user to choose SimpleList implementation

Compare ArraySimpleList vs LinkeSimpleList performance

Set Building Times

Remark on == vs .equals()

Consider the following code:

Integer i = new Integer(10);
Integer j = new Integer(10);

if (i == j) {
    System.out.println("They're the same!");
} else {
    System.out.println("They're not the same!");
}

What does it print?

What about now?

Integer i = new Integer(10);
Integer j = new Integer(10);

if (i.equals(j)) {
    System.out.println("They're the same!");
} else {
    System.out.println("They're not the same!");
}

Question

What is the difference between i == j and i.equals(j)?

Terminology

  • i == j connotes literal equality
    • i and j refer to the same object
  • i.equals(j) connotes semantic equivalence
    • i and j behave in the same way

Usage

When defining a new class, by default == and .equals have the same effect:

  • both are true only when their arguments refer to the same object instance

We can override the default implementation to make equals method do something different

  • E.g., for Integers, i.equals(j) if i and j store the same int value

For SimpleUSet<E>

Must be sure to use equals method, not ==!

SimpleUSet<Integer> set;
set.add(new Integer(2));
set.add(new Integer(2));

Result should be that set contains only one element whose value is 2.

Find and Remove

find and remove return instances stored by the set

E.g., this:

public E find(E x) {
    E y;
    for(int i = 0; i < list.size(); ++i) {
        y = list.get(i);
        if (x.equals(y)) {
            return y;
        }
    return null;
}

Not this:

public E find(E x) {
    E y;
    for(int i = 0; i < list.size(); ++i) {
        y = list.get(i);
        if (x.equals(y)) {
            return x;
        }
    return null;
}