Lecture 05: More List Performance

Announcement

Virtual office hours today (after class)

Overview

  1. General Advice
  2. Recap of Last Time
  3. A LinkedSimpleList and Performance Comparison
  4. Relationships Between ADTs
    • Deques
    • Queues
    • Stacks

General Advice

  • Start assignments early
  • Plan before code
    • computer programs cannot solve any problem that cannot (in principle) be solved by hand
  • Compile often
  • Write methods to print state of data structures
  • Test code as you go

Example workflow in Implementing Interfaces in Java

Debugging

Estimates: software engineers spend 75–90% of their time debugging!

  • plan accordingly

Debugging is an essential part of the development process:

  • incorperate tools to debug in your code as you write it
    • e.g. print statements at beginning/end of methods
    • methods to print/display state of fields
    • make a simple tester program before implementing methods
  • test inidividual methods as you write them

Last Time

Considered ArraySimpleList implementation of SimpleList

  • analyzed running time of building a list by appending to back
  • saw huge difference in performance between two implementations of increaseCapacity method

Before & After

Before:

    private void increaseCapacity() {	
	Object[] bigContents = new Object[capacity + 1];
	for (int i = 0; i < capacity; ++i) {
	    bigContents[i] = contents[i];
	}
	contents = bigContents;
	capacity = capacity + 1;
    }

After:

    private void increaseCapacity() {	
	Object[] bigContents = new Object[2 * capacity];
	for (int i = 0; i < capacity; ++i) {
	    bigContents[i] = contents[i];
	}
	contents = bigContents;
	capacity = 2 * capacity;
    }

Performance Before

Performance After

Why Such a Big Difference?

Another Look at Add Method

    public void add(int i, E x) {
	if (i > size || i < 0) {
	    throw new IndexOutOfBoundsException();
	}

	if (size == capacity) {
	    increaseCapacity();
	}

	++size;

	Object cur = x;
	for (int j = i; j < size; ++j) {
	    Object next = contents[j];
	    contents[j] = cur;
	    cur = next;
	}
    }

Performance of adding at index 0 vs size?

Question

How fast is building an ArraySimpleList by repeatedly adding at index 0?

Running Times

Why is Poor Performance Expected?

    public void add(int i, E x) {
	if (i > size || i < 0) {
	    throw new IndexOutOfBoundsException();
	}

	if (size == capacity) {
	    increaseCapacity();
	}

	++size;

	Object cur = x;
	for (int j = i; j < size; ++j) {
	    Object next = contents[j];
	    contents[j] = cur;
	    cur = next;
	}
    }

LinkedSimpleList Implementation

A Linked List List Implementation

Recall the “linked list” data structure

Representing a List as Linked List

Implementation Notes

  • How to get(i)?
  • How to add(i, y)?
  • How to remove(i, y)?

Java implementation

Performance: Add at End

Performance: Add at Front

Question 1

Why should we expect to see this trend?

Performance: Add at Random

Question 2

Is trend what you’d expect? Why or why not?

Other List-like ADTs

Other ADTs

  • List
  • Stack
  • Queue
  • Deque

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?