CS 61B: Data Structures

CS 61B contains content regarding data structures (e.g. lists, queues, trees, etc.) and algorithms for sorting and searching. The course also offers an introduction to the Java programming language. Below are the notes that I compiled from when I took CS 61B at UC Berkeley.


Open Note in New Page

Lecture01.md

Lecture 1: Welcome to 61B

8/26/2020

Hello World

# In Python print("hello world") // In Java public class HelloWorld { public static void main(String[] args) { System.out.println("hello world"); } } // Output: hello world
# In Python x = 0 while x < 10: print(x) x = x + 1 // In Java public class HelloNumbers { public static void main(String[] args) { int x = 0; // Must declare variables, variable types can never change while (x < 10) { System.out.println(x); x = x + 1; } } }
# In Python def larger(x, y): """Returns the larger of x and y""" if (x > y): return x return y print (larger(-5, 10)) // In Java public class LargerDemo { /** Returns the larger of x and y. */ public static larger(int x, int y) { if (x > y) { return x; } return y; } public static void main(String[] args) { System.out.println(larger(-5, 10)); } }

Java and Object Orientation

Java and Static Typing

Reflections on Static Typing

Welcome to 61B 2019

What is 61B About?

Why Study Algorithms or Data Structures?

Why Study Algorithms or Data Structures?

Why Study Algorithms or Data Structures?

Open Note in New Page

Lecture02.md

Lecture 2: Defining and Using Classes

8/28/2020

Compilation

Compiling and running code from the terminal: $ javac HelloWorld.java $ ls HelloWorld.java HelloWorld.class $ java HelloWorld Hello World!

Compilation

Defining and Instantiating Classes

/** Dog.java file */ public class Dog { public static void makeNoise() { System.out.println("Bark!"); } } /** Can't be run directly, no main method */ /** DogLauncher.java file */ /** The DogLauncher class will test drive the Dog class */ public class DogLauncher { public static void main(String[] args) { Dog.makeNoise(); } } $ java DogLauncher Bark!

Dog

Object Instantiation

public class Dog { public int weightInPounds; // An instance variable /** One integer constructor for dogs. */ public Dog(int w) { // Constructor (similar to __init__) weightInPounds = w; } public void makeNoise() { // Non-static method, instance method if (weightInPounds < 10) { System.out.println("yip!"); } else if (weightInPounds < 30) { System.out.println("bark."); } else { System.out.println("wooooof!"); } } } /** DogLauncher.java file */ /** The DogLauncher class will test drive the Dog class */ public class DogLauncher { public static void main(String[] args) { Dog smallDog; // Declaration of a Dog instance new Dog(20); // Instantiation of a Dog instance smallDog = new Dog(5); // Instantiation and Assignment Dog mediumDog = new Dog(25); // Declaration, Instantiation, and Assignment d.makeNoise(); // Invocation of the 25 lb Dog's makeNoise method } } $ java DogLauncher bark.

Defining a Typical Class (Terminology)

Arrays of Objects

Dog[] dogs = new Dog[2]; // Creates an array of Dogs of size 2 dogs[0] = new Dog(8); dogs[1] = new Dog(20); dogs[0].makeNoise(); // Yipping occurs

Static vs Instance Methods

Static vs Non-static

Why Static Methods?

public class Dog { public int weightInPounds; // An instance variable /** A static variable that applies to all dog instances */ public static String binomen = "Canis familiaris"; /** One integer constructor for dogs. */ public Dog(int w) { // Constructor (similar to __init__) weightInPounds = w; } public void makeNoise() { // Non-static method, instance method if (weightInPounds < 10) { System.out.println("yip!"); } else if (weightInPounds < 30) { System.out.println("bark."); } else { System.out.println("wooooof!"); } } public static Dog maxDog(Dog d1, Dog d2) { if (d1.weightInPounds > d2.weightInPounds) { return d1; } return d2; } public Dog maxDog(Dog d2) { if (this.weightInPounds > d2.weightInPounds) { return this; } return d2; } } public class DogLauncher { public static void main(String[] args) { Dog d = new Dog(15); Dog d2 = new Dog(100); Dog bigger = Dog.maxDog(d, d2); bigger.makeNoise(); Dog bigger2 = d.maxDog(d2); bigger2.makeNoise(); System.out.println(d.binomen); System.out.println(Dog.binomen); } } $ java DogLauncher woooooof! woooooof! Canis familiaris Canis familiaris

Static vs. Non-static

public static void main(String[] args)

One Special Role for String: Command Line Arguments

public class ArgsDemo { /** Prints out the -th command line argument. */ public static void main(String[] args) { System.out.println(args[0]); } } $ java ArgsDemo hello some args hello

ArgsSum Exercise

public class ArgsSum { public static void main(String[] args) { int N = args.length; int i = 0; int sum = 0; while (i < N) { sum = sums + Integer.parseInt(args[i]); i = i + 1; } } }

Using Libraries (e.g. StdDraw, In)

Java Libraries

Open Note in New Page

Lecture03.md

Lecture 3: References, Recursion, and Lists

8/31/2020

Primitive Types

Variables in Java

Walrus a = new Walrus(1000, 8.3); Walrus b; b = a; b.weight = 5; System.out.println(a); System.out.println(b); Result: 5 5
int x = 5; int y; y = x; x = 2; System.out.println(x); System.out.println(y); Result: 2 5

Bits

Declaring a Variable (simplified)

int x; double y; x = -1431195969; y = 567213.112

Simplified Box Notation

The Golden Rule of Equals (GRoE)

Reference Types

Reference Types

Class Instantiations

public class Walrus { public int weight; public double tuskSize; public Walrus(int w, double ts) { weight = w; tuskSize = ts; } }

Reference Type Variable Declarations

Reference Types Obey the Golden Rule of Equals

Parameter Passing

The Golden Rule of Equals (and Parameter Passing)

public static double average(double a, double b) { return (a + b) / 2; } public static void main(String[] args) { double x = 5.5; double y = 10.5; double avg = average(x, y); }

The Golden Rule: Summary

Instantiation of Arrays

Declaration and Instantiation of Arrays

Assignment of Arrays

IntList and Linked Data Structures

IntList

public class IntList { public int first; public IntList rest; public IntList(int f, IntList r) { first = f; rest = r; } public static void main(String[] args) { IntList L = new IntList(15, null); L = new IntList(10, L); L = new IntList(5, L); } }

IntList

public class IntList { public int first; public IntList rest; public IntList(int f, IntList r) { first = f; rest = r; } public int size() { // Return the size of the list using... recursion! if (rest == null) { return 1; } return 1 + this.rest.size(); } public int iterativeSize() { // Return the size of the list using no recursion IntList p = this; int totalSize = 0; while (p != null) { totalSize += 1; p = p.rest; } return totalSize; } public static void main(String[] args) { IntList L = new IntList(15, null); L = new IntList(10, L); L = new IntList(5, L); } }

Challenge

public class IntList { public int first; public IntList rest; public IntList(int f, IntList r) { first = f; rest = r; } public int size() { // Return the size of the list using... recursion! if (rest == null) { return 1; } return 1 + this.rest.size(); } public int iterativeSize() { // Return the size of the list using no recursion IntList p = this; int totalSize = 0; while (p != null) { totalSize += 1; p = p.rest; } return totalSize; } public int get(int i) { // Returns the ith item of this IntList if (i == 0) { return first; } return rest.get(i - 1); } public static void main(String[] args) { IntList L = new IntList(15, null); L = new IntList(10, L); L = new IntList(5, L); } }

Open Note in New Page

Lecture04.md

Lecture 4: SLLists, Nested Classes, Sentinel Nodes

9/2/2020

public class IntList { public int first; public IntList rest; public IntList(int f, IntList r) { first = f; rest = r; } }

Improvement #1: Rebranding and Culling

public class IntNode { public int item; public IntNode next; public IntNode(int i, IntNode n) { item = i; next = n; } }

Improvement #2: Bureaucracy

public class IntNode { public int item; public IntNode next; public IntNode(int i, IntNode n) { item = i; next = n; } } // An SLList is a list of integers, which hides the terrible truth of the nakedness within public class SLList { public IntNode first; public SLList(int x) { first = new IntNode(x, null); } // Adds x to the front of the list public void addFirst(int x) { first = new IntNode(x, first); } // Returns the first item in the list public int getFirst() { return first.item; } public static void main(String[] args) { // Creates a list of one integer, namely 10 SLList L = new SLList(10); L.addFirst(10); // Adds 10 to front of list L.addFirst(5); // Adds 5 to front of list int x = L.getFirst(); } }

The Basic SLList and Helper IntNode Class

A Potential SLList Danger

SLList L = new SLList(15); L.addFirst(10); L.first.next.next = L.first.next;
public class SLList { private IntNode first; public SLList(int x) { first = new IntNode(x, null); } // Adds x to the front of the list public void addFirst(int x) { first = new IntNode(x, first); } // Returns the first item in the list public int getFirst() { return first.item; } public static void main(String[] args) { // Creates a list of one integer, namely 10 SLList L = new SLList(10); L.addFirst(10); // Adds 10 to front of list L.addFirst(5); // Adds 5 to front of list int x = L.getFirst(); } }

Why Restrict Access?

Improvement #4: Nesting a Class

public class SLList { private static class IntNode { // static: never looks outwards public int item; public IntNode next; public IntNode(int i, IntNode n) { item = i; next = n; } } private IntNode first; public SLList(int x) { first = new IntNode(x, null); } // Adds x to the front of the list public void addFirst(int x) { first = new IntNode(x, first); } // Returns the first item in the list public int getFirst() { return first.item; } public static void main(String[] args) { // Creates a list of one integer, namely 10 SLList L = new SLList(10); L.addFirst(10); // Adds 10 to front of list L.addFirst(5); // Adds 5 to front of list int x = L.getFirst(); } }

Why Nested Classes?

Static Nested Classes

Adding More SLList Functionality

public class SLList { private static class IntNode { // static: never looks outwards public int item; public IntNode next; public IntNode(int i, IntNode n) { item = i; next = n; } } private IntNode first; public SLList(int x) { first = new IntNode(x, null); } // Adds x to the front of the list public void addFirst(int x) { first = new IntNode(x, first); } // Returns the first item in the list public int getFirst() { return first.item; } // Adds an item to the end of the list public void addLast(int x) { IntNode p = first; while (p.next != null) { p = p.next; } p.next = new IntNode(x, null); } // Returns the size of the list that starts at IntNode p private static int size(IntNode p) { if (p.next == null) { return 1; } return 1 + size(p.next); } public int size() { return size(first); } public static void main(String[] args) { // Creates a list of one integer, namely 10 SLList L = new SLList(10); L.addFirst(10); // Adds 10 to front of list L.addFirst(5); // Adds 5 to front of list L.addLast(20); System.out.println(L.size()) } }

Efficiency of Size

Improvement #5: Fast size()

public class SLList { private static class IntNode { // static: never looks outwards public int item; public IntNode next; public IntNode(int i, IntNode n) { item = i; next = n; } } private IntNode first; private int size; public SLList(int x) { first = new IntNode(x, null); size = 1; } // Adds x to the front of the list public void addFirst(int x) { first = new IntNode(x, first); size += 1; } // Returns the first item in the list public int getFirst() { return first.item; } // Adds an item to the end of the list public void addLast(int x) { size += 1; IntNode p = first; while (p.next != null) { p = p.next; } p.next = new IntNode(x, null); } public int size() { return size; } public static void main(String[] args) { // Creates a list of one integer, namely 10 SLList L = new SLList(10); L.addFirst(10); // Adds 10 to front of list L.addFirst(5); // Adds 5 to front of list L.addLast(20); System.out.println(L.size()) } }

Improvement #6a: Representing the Empty List

public class SLList { private static class IntNode { // static: never looks outwards public int item; public IntNode next; public IntNode(int i, IntNode n) { item = i; next = n; } } private IntNode first; private int size; // Creates an empty SLList public SLList() { first = null; size = 0; } public SLList(int x) { first = new IntNode(x, null); size = 1; } // Adds x to the front of the list public void addFirst(int x) { first = new IntNode(x, first); size += 1; } // Returns the first item in the list public int getFirst() { return first.item; } // Adds an item to the end of the list public void addLast(int x) { size = size + 1; if (first == null) { first = new IntNode(x, null); return; } IntNode p = first; while (p.next != null) { p = p.next; } p.next = new IntNode(x, null); } public int size() { return size; } public static void main(String[] args) { // Creates a list of one integer, namely 10 SLList L = new SLList(); L.addFirst(10); // Adds 10 to front of list L.addFirst(5); // Adds 5 to front of list L.addLast(20); System.out.println(L.size()) } }

Tip for Being a GOod Programmer: Keep Code Simple

addLast's Fundamental Problem

Improvement #6b: Representing the Empty List Use a Sentinel Node

public class SLList { private static class IntNode { // static: never looks outwards public int item; public IntNode next; public IntNode(int i, IntNode n) { item = i; next = n; } } // The first item (if it exists) is at sentinel.next private IntNode sentinel; private int size; // Creates an empty SLList public SLList() { sentinel = new IntNode(69, null); size = 0; } public SLList(int x) { sentinel = new IntNode(69, null); sentinel.next = new IntNode(x, null); size = 1; } // Adds x to the front of the list public void addFirst(int x) { sentinel.next = new IntNode(x, sentinel.next); size = size + 1; } // Returns the first item in the list public int getFirst() { return sentinel.next.item; } // Adds an item to the end of the list public void addLast(int x) { size = size + 1; IntNode p = sentinel; while (p.next != null) { p = p.next; } p.next = new IntNode(x, null); } public int size() { return size; } public static void main(String[] args) { // Creates a list of one integer, namely 10 SLList L = new SLList(); L.addFirst(10); // Adds 10 to front of list L.addFirst(5); // Adds 5 to front of list L.addLast(20); System.out.println(L.size()) } }

Sentinel Node

addLast (with Sentinel Node)

Invariants

Open Note in New Page

Lecture05.md

Lecture 5: DLLists, Arrays

9/4/2020

Summary of SLLists So Far

One Downside of SLLists

Improvement #7: Fast addLast

Why a Last Pointer Isn't Enough

.last is not enough

Improvement #7: .last and ???

Doubly Linked Lists (Naive)

Doubly Linked Lists (Double Sentinel)

Doubly Linked Lists (Circular Sentinel)

Improvement #8: Fancier Sentinel Nodes

Generic Lists

Integer Only Lists

public class SLList<LochNess> { private class StuffNode { public LochNess item; public StuffNode next; public StuffNode(LochNess i, StuffNode n) { item = i; next = n; } } private StuffNode first; private int size; ... ... ... } public class SLListLauncher { public static void main(String[] args) { SLList<String> s1 = new SLList<>("bone"); s1.addFirst("thugs"); } }

SLists

Generics

Array Overview

Getting Memory Boxes

Arrays

Arrays

Array Basics:

int[] z = null; int[] x, y; x = new int[]{1, 2, 3, 4, 5}; y = x; x = new int[]{-1, 2, 5, 4, 99}; y = new int[3]; z = new int[0]; int xL = x.length; String[] s = new String[6]; s[4] = "ketchup"; s[x[3] - x[1]] = "muffins"; int[] b = {9, 10, 11}; System.arraycopy(b, 0, x, 3, 2);

Array Copy

2D Arrays

Arrays of Array Addresses

int[][] pascalsTriangle; pascalsTriangle = new int[4][]; int[] rowZero = pascalsTriangle[0]; pascalsTriangle[0] = new int[]{1}; pascalsTriangle[1] = new int[]{1, 1}; pascalsTriangle[2] = new int[]{1, 2, 1}; pascalsTriangle[3] = new int[]{1, 3, 3, 1}; int[] rowTwo = pascalsTriangle[2]; rowTwo[1] = -5; int[][] matrix; matrix = new int[4][]; matrix = new int[4][4]; int[][] pascalAgain = new int[][]{{1}, {1, 1}, {1, 2, 1}, {1, 3, 3, 1}};

Arrays vs. Classes

Arrays vs. Classes

Another view

int k = x[indexOfInterest]; double m = p.fieldOfInterest; // Won't work double z = p[fieldOfInterest]; // Won't work // No (sane) way to use field of interest double w = p.mass; // Works fine

Open Note in New Page

Lecture06.md

Lecture 6: ALists, Resizing, vs. SLists

9/9/2020

A Last Look at Linked Lists

Doubly Linked Lists

Arbitrary Retrieval

Naive Array Lists

Random Access in Arrays

Our Goal: AList.java

public class AList { private int[] items; private int size; /** Creates an empty list. */ public AList() { items = new int[100]; size = 0; } /** Inserts X into the back of the list */ public void addLast(int x) { items[size] = x; size = size + 1; } /** Returns the item from the back of the list. */ public int getLast() { return items[size-1]; } /** Gets the ith item from the List (0 is the front) */ public int get(int i) { return items[i]; } /** Returns the number of items in the list. */ public int size() { return size; } }

Naive AList Code

The Abstract vs. the Concrete

Deletion

public class AList { private int[] items; private int size; /** Creates an empty list. */ public AList() { items = new int[100]; size = 0; } /** Inserts X into the back of the list */ public void addLast(int x) { items[size] = x; size = size + 1; } /** Returns the item from the back of the list. */ public int getLast() { return items[size-1]; } /** Gets the ith item from the List (0 is the front) */ public int get(int i) { return items[i]; } /** Returns the number of items in the list. */ public int size() { return size; } /** Deletes item from back of the list and returns deleted item */ public int removeLast() { int x = getLast(); items[size-1] = 0; // Not necessary to preserve invariants -> not necessary for correctness size = size - 1; return x; } }

Resizing Arrays

The Mighty AList

Array Resizing

Implementation

public class AList { private int[] items; private int size; /** Creates an empty list. */ public AList() { items = new int[100]; size = 0; } /** Resizes the underlying array to the target capacity */ private void resize(int capacity) { int[] a = new int[capacity] System.arraycopy(items, 0, a, 0, size); items = a; } /** Inserts X into the back of the list */ public void addLast(int x) { if (size == items.length) { resize(size + 1); } items[size] = x; size = size + 1; } /** Returns the item from the back of the list. */ public int getLast() { return items[size-1]; } /** Gets the ith item from the List (0 is the front) */ public int get(int i) { return items[i]; } /** Returns the number of items in the list. */ public int size() { return size; } /** Deletes item from back of the list and returns deleted item */ public int removeLast() { int x = getLast(); items[size-1] = 0; // Not necessary to preserve invariants -> not necessary for correctness size = size - 1; return x; } }

Basic Resizing Analysis

Runtime and Space Usage Analysis

Array Resizing

Runtime and Space Usage Analysis

Resizing Slowness

Making AList Fast

Fixing the Resizing Performance Bug

public class AList { private int[] items; private int size; /** Creates an empty list. */ public AList() { items = new int[100]; size = 0; } /** Resizes the underlying array to the target capacity */ private void resize(int capacity) { int[] a = new int[capacity] System.arraycopy(items, 0, a, 0, size); items = a; } /** Inserts X into the back of the list */ public void addLast(int x) { if (size == items.length) { resize(size * 2); // A subtle fix!!! } items[size] = x; size = size + 1; } /** Returns the item from the back of the list. */ public int getLast() { return items[size-1]; } /** Gets the ith item from the List (0 is the front) */ public int get(int i) { return items[i]; } /** Returns the number of items in the list. */ public int size() { return size; } /** Deletes item from back of the list and returns deleted item */ public int removeLast() { int x = getLast(); items[size-1] = 0; // Not necessary to preserve invariants -> not necessary for correctness size = size - 1; return x; } }

(Probably) Surprising Fact

public void addLast(int x) { if (size == items.length) { resize(size * 2); // A subtle fix!!! } items[size] = x; size = size + 1; }

Performance Problem #2

Memory Efficiency

Generic AList

There's a Problem

public class AList<Item> { private Item[] items; private int size; /** Creates an empty list. */ public AList() { items = (Item[]) new Object[100]; size = 0; } /** Resizes the underlying array to the target capacity */ private void resize(int capacity) { Item[] a = (Item[]) new Object[capacity] System.arraycopy(items, 0, a, 0, size); items = a; } /** Inserts X into the back of the list */ public void addLast(int x) { if (size == items.length) { resize(size * 2); // A subtle fix!!! } items[size] = x; size = size + 1; } /** Returns the item from the back of the list. */ public Item getLast() { return items[size-1]; } /** Gets the ith item from the List (0 is the front) */ public Item get(int i) { return items[i]; } /** Returns the number of items in the list. */ public int size() { return size; } /** Deletes item from back of the list and returns deleted item */ public Item removeLast() { int x = getLast(); items[size-1] = null; size = size - 1; return x; } }

Generic ALists (similar to generic SLists)

Nulling Out Deleted Items

Open Note in New Page

Lecture07.md

Lecture 7: Testing

9/11/2020

A New Way

How Does a Programmer Know That Their Code Works?

Sorting: The McGuffin for Our Testing Adventure

The New Way

Ad Hoc Testing vs. JUnit

Ad Hoc Test

public class TestSort { /** Test the Sort.sort method */ public static void testSort() { String[] input = {"i", "have", "an", "egg"}; String[] expected = {"an", "egg", "have", "i"}; Sort.sort(input); for (int i = 0; i < input.length; i += 1) { if (!input[i].equals(expected[i])) { System.out.println("Mismatch in position " + i); return; } } if (java.utils.Arrays.equals(input, expected)) { System.out.println("Error! There seems to be a problem with Sort.sort."); } } public static void main(String[] args) { testSort(); } }

JUnit: A Library for Making Testing Easier

public class TestSort { /** Test the Sort.sort method */ public static void testSort() { String[] input = {"i", "have", "an", "egg"}; String[] expected = {"an", "egg", "have", "i"}; Sort.sort(input); org.junit.Assert.assertArrayEquals(expected, input); } public static void main(String[] args) { testSort(); } }

Selection Sort

Back to Sorting: Selection Sort

public class Sort { /** Sorts strings recursively */ public static void sort(String[] x) { // Find the smallest item // Move it to the front // Selection sort the rest int smallestIndex = findSmallest(x); swap(x, 0, smallestIndex); } /** Swap item a with b */ public static void swap(String[] x, int a, int b) { String temp = x[a]; x[a] = x[b]; x[b] = temp; } /** Returns the index of the smallest String in x */ public static int findSmallest(String[] x) { int smallestIndex = 0; for (int i = 0; i < x.length; i += 1) { int cmp = x[i].compareTo(x[smallestIndex]); if (cmp < 0) { smallestIndex = i; } return smallestIndex; } } } public class TestSort { /** Test the Sort.sort method */ public static void testSort() { String[] input = {"i", "have", "an", "egg"}; String[] expected = {"an", "egg", "have", "i"}; Sort.sort(input); org.junit.Assert.assertArrayEquals(expected, input); } /** Test the Sort.findSmallest method */ public static void testFindSmallest() { String[] input = {"i", "have", "an", "egg"}; int expected = 2; int actual = Sort.findSmallest(input); org.junit.Assert.assertEquals(expected, actual); String[] input2 = {"there", "are", "many", "pigs"}; int expected2 = 1; int actual = Sort.findSmallest(input2); org.junit.Assert.assertEquals(expected2, actual2); } public static void testSwap() { String[] input = {"i", "have", "an", "egg"}; int a = 0; int b = 2; String[] expected = {"an", "have", "i", "egg"}; Sort.swap(input, input, b); org.junit.Assert.assertArrayEquals(expected, input); } public static void main(String[] args) { testSwap(); testFindSmallest(); testSort(); } }

The Evolution of Our Design

public class Sort { /** Sorts strings recursively */ public static void sort(String[] x) { sort(x, 0); } /** Sorts x starting at position start */ private static void sort(String[] x, int start) { if (start == x.length) { return; } int smallestIndex = findSmallest(x, start); swap(x, start, smallestIndex); sort(x, start + 1); } /** Swap item a with b */ public static void swap(String[] x, int a, int b) { String temp = x[a]; x[a] = x[b]; x[b] = temp; } /** Returns the index of the smallest String in x. Starting at start */ public static int findSmallest(String[] x, int start) { int smallestIndex = start; for (int i = start; i < x.length; i += 1) { int cmp = x[i].compareTo(x[smallestIndex]); if (cmp < 0) { smallestIndex = i; } return smallestIndex; } } } public class TestSort { /** Test the Sort.sort method */ public static void testSort() { String[] input = {"i", "have", "an", "egg"}; String[] expected = {"an", "egg", "have", "i"}; Sort.sort(input); org.junit.Assert.assertArrayEquals(expected, input); } /** Test the Sort.findSmallest method */ public static void testFindSmallest() { String[] input = {"i", "have", "an", "egg"}; int expected = 2; int actual = Sort.findSmallest(input, 0); org.junit.Assert.assertEquals(expected, actual); String[] input2 = {"there", "are", "many", "pigs"}; int expected2 = 2; int actual2 = Sort.findSmallest(input2, 2); org.junit.Assert.assertEquals(expected2, actual2); } /** Test the Sort.swap method */ public static void testSwap() { String[] input = {"i", "have", "an", "egg"}; int a = 0; int b = 2; String[] expected = {"an", "have", "i", "egg"}; Sort.swap(input, input, b); org.junit.Assert.assertArrayEquals(expected, input); } public static void main(String[] args) { testSwap(); testFindSmallest(); testSort(); } }

The Evolution of Our Design

Reflections on the Process

And We're Done!

Simpler JUnit Tests

Simple JUnit

Better JUnit

Even Better JUnit

public class Sort { /** Sorts strings recursively */ public static void sort(String[] x) { sort(x, 0); } /** Sorts x starting at position start */ private static void sort(String[] x, int start) { if (start == x.length) { return; } int smallestIndex = findSmallest(x, start); swap(x, start, smallestIndex); sort(x, start + 1); } /** Swap item a with b */ public static void swap(String[] x, int a, int b) { String temp = x[a]; x[a] = x[b]; x[b] = temp; } /** Returns the index of the smallest String in x. Starting at start */ public static int findSmallest(String[] x, int start) { int smallestIndex = start; for (int i = start; i < x.length; i += 1) { int cmp = x[i].compareTo(x[smallestIndex]); if (cmp < 0) { smallestIndex = i; } return smallestIndex; } } } import org.junit.Test; import static org.junit.Assert.*; public class TestSort { /** Test the Sort.sort method */ @org.junit.Test public void testSort() { String[] input = {"i", "have", "an", "egg"}; String[] expected = {"an", "egg", "have", "i"}; Sort.sort(input); assertArrayEquals(expected, input); } /** Test the Sort.findSmallest method */ @org.junit.Test public void testFindSmallest() { String[] input = {"i", "have", "an", "egg"}; int expected = 2; int actual = Sort.findSmallest(input, 0); assertEquals(expected, actual); String[] input2 = {"there", "are", "many", "pigs"}; int expected2 = 2; int actual2 = Sort.findSmallest(input2, 2); assertEquals(expected2, actual2); } /** Test the Sort.swap method */ @org.junit.Test public void testSwap() { String[] input = {"i", "have", "an", "egg"}; int a = 0; int b = 2; String[] expected = {"an", "have", "i", "egg"}; Sort.swap(input, input, b); assertArrayEquals(expected, input); } }

Testing Philosophy

Correctness Tool #1: Autograder

Autograder Driven Development (ADD)

Correctness Tool #2: Unit Tests

Test-Driven Development (TDD)

A Tale of Two Workflows

Correctness Tool #3: Integration Testing

Parting Thoughts

Open Note in New Page

Lecture08.md

Lecture 8: Inheritance, Implements

9/14/2020

The Desire for Generality

AList and SList

Using ALists and SLists: WordUtils.java

Method Overloading in Java

public static String longest(AList<String> list) { ... } public static String longest(SLList<String> list) { ... }

The Downsides

Hypernyms, Hyponyms, and Interface Inheritance

Hypernyms

Hypernym and Hyponym

Simple Hyponymic Relationships in Java

Step 1: Defining a List61B.java

public interface List61B<Item> { public void addLast(Item x); public Item getLast(); public Item get(int i); public int size(); public Item removeLast(); public void insert(Item x, int position); public Item getFirst(); }

Step 2: Implementing the List61B Interface

public class AList<Item> implements List61B<Item> { ... } public class SLList<Item> implements List61B<Item> { ... }
public class WordUtils { public static String longest(List61B<String> list) { ... } }

Overriding vs. Overloading

Method Overriding

public class Math { public int abs(int a) public double abs(double a) }

Optional Step 2B: Adding the @Override Annotation

public class AList<Item> implements List61B<Item> { @Override public Item getItem(int a) { ... } }

Interface Inheritance

Interface Inheritance

Copying the Bits

public static void main(String[] args) { List61B<String> someList = new SLList<>(); someList.addFirst("elk"); }

Implementation Inheritance: Default Methods

Implementation Inheritance

public interface List61B<Item> { public void addLast(Item x); public Item getLast(); public Item get(int i); public int size(); public Item removeLast(); public void insert(Item x, int position); public Item getFirst(); /** Prints out the entire List. */ default public void print() { for (int i = 0; i < size(); i += 1) { System.out.print(get(i) + ' '); } System.out.println(); } }

Is the print() method efficient?

Overriding Default Methods

Overriding Default Methods

public class SLList<Item> { @Override public void print() { for (Node p = sentinel.next; p != null; p = p.next) { System.out.print(p.item + ' '); } } }

Dynamic Method Selection

Static Type vs. Dynamic Type

Dynamic Method Selection For Overridden Methods

More Dynamic Method Selection, Overloading vs. Overriding

The Method Selection Algorithm

Is a vs Has a, Interface vs Implementation Inheritances

Interface vs. Implementation Inheritance

Dangers of Implementation Inheritance

Open Note in New Page

Lecture09.md

Lecture 9: Extends, Casting, Higher Order Functions

9/16/2020

Implementation Inheritance: Extends

The Extends Keyword

RotatingSLList

public class RotatingSLList<Item> extends SLList<Item> { // Rotates list to the right public void rotateRight() { Item x = removeLast(); addFirst(x); } }

Another Example: VengefulSLList

public class VengefulSLList<Item> extends SLList<Item> { SLList<Item> deletedItems; public VengefulSLList() { super(); // Optional line deletedItems = new SLList<Item>(); } @Override public Item removeLast() { Item x = super.removeLast(); // Calls Superclass's version of removeLast() deletedItems.addLast(x); return x; } // Prints deleted items public void printLostItems() { deletedItems.print(); } }

Constructor Behavior is Slightly Weird

Calling Other Constructors

public class VengefulSLList<Item> extends SLList<Item> { SLList<Item> deletedItems; public VengefulSLList() { super(); // Optional line deletedItems = new SLList<Item>(); } public VengefulSLList(Item x) { super(x); // NOT OPTIONAL! (calls no-argument constructor otherwise) deletedItems = new SLList<Item>(); } }

The Object Class

Is-a vs. Has-A

Encapsulation

Complexity: The Enemy

Modules and Encapsulation

A Cautionary Tale

Abstraction Barriers

Implementation Inheritance Breaks Encapsulation

public void bark() { barkMany(1); } public void barkMany(int N) { for (int i = 0; i < N; i += 1) { System.out.println("bark"); } } @Override public void barkMany(int N) { System.out.println("As a dog, I say: ") { for (int i = 0; i < N; i += 1) { bark(); // calls inherited bark method } } }

Type Checking and Casting

Reminder: Dynamic Method Selection

Compile-Time Type Checking

Compile-Time Types and Expressions

Compile-Type Types and Expressions

Poodle frank = new Poodle("Frank", 5); Poodle frankJr = new Poodle("Frank Jr." 15); dog largerDog = maxDog(frank, frankJr); Poodle largerPoodle = maxDog(frank, frankJr); // Compilation Error! // RHS has compile-time type Dog

Casting

Poodle frank = new Poodle("Frank", 5); Poodle frankJr = new Poodle("Frank Jr." 15); dog largerDog = maxDog(frank, frankJr); Poodle largerPoodle = (Poodle) maxDog(frank, frankJr); // Compilation OK! // RHS has compile-time type Poodle
Poodle frank = new Poodle("Frank", 5); Malamute frankSr = new Malamute("Frank Sr.", 100); Poodle largerPoodle = (Poodle) maxDog(frank, frankSr);

Higher Order Functions (A First Look)

Higher Order Functions

def tenX(x): return 10*x def do_twice(f, x): return f(f(x)) print(do_twice(tenX, 2))

Higher Order Functions in Java 7

// Represents a function that takes in an integer, and returns an integer public interface IntUnaryFunction { int apply(int x); }
public class TenX implements IntUnaryFunction { /** Returns ten times the argument */ public int apply(int x) { return 10 * x; } }
// Demonstrates higher order functions in Java public class HofDemo { public static int doTwice(IntUnaryFunction f, int x) { return f.apply(f.apply(x)); } public static void main(String[] args) { IntUnaryFunction tenX = new TenX(); System.out.println(doTwice(tenX, 2)); } }

Implementation Inheritance Cheatsheet

Open Note in New Page

Lecture10.md

Lecture 10: Subtype Polymorphism vs. HoFs

9/18/2020

Static Methods, Variables, and Inheritance

Subtype Polymorphism

Subtype Polymorphism

Subtype Polymorphism vs. Explicit Higher Order Functions

def print_larger(x, y, compare, stringify): if compare(x, y): return stringify(x) return stringify(x)
def print_larger(x, y): if x.largerThan(y): return x.str() return y.str()

DIY Comparison

shoutkey.com/TBA

Writing a General Max Function: The Fundamental Problem

Solution

public static OurComparable max(OurComparable[] items) {...}
public interface OurComparable { /** Return negative number if this is less than o * Return 0 if this is equal to o * Return positive number if this if greater than o */ public int compareTo(Object obj); } public class Dog implements OurComparable { private String name; private int size; public Dog(String n, int s) { name = n; size = s; } public void bark() { System.out.println(name + " says: bark"); } // Returns negative number if this dog is less than the dog pointed by o, and so forth public int compareTo(Object o) { Dog otherDog = (Dog) o; return this.size - otherDog.size; } } public class Maximizer { public static OurComparable max(OurComparable[] items) { int maxDex = 0; for (int i = 0; i < items.length; i += 1) { int cmp = items[i].compareTo(items[maxDex]) if (cmp > 0) { maxDex = i; } } return items[maxDex]; } }

The OurComparable Interface

General Maximization Function Through Inheritance

Comparables

The Issues with OurComparable

public class Dog implements Comparable<Dog> { ... // Returns negative number if this dog is less than the dog pointed by o, and so forth public int compareTo(Dog otherDog) { return this.size - otherDog.size; } } public class Maximizer { public static Comparable max(Comparable[] items) { int maxDex = 0; for (int i = 0; i < items.length; i += 1) { int cmp = items[i].compareTo(items[maxDex]) if (cmp > 0) { maxDex = i; } } return items[maxDex]; } }

Comparable Advantages

Comparators

Natural Order

Additional Orders in Java

import java.util.Comparator; public class Dog implements OurComparable { ... // Returns negative number if this dog is less than the dog pointed by o, and so forth public int compareTo(Object o) { Dog otherDog = (Dog) o; return this.size - otherDog.size; } private static class NameComparator implements Comparator<Dog> { public int compare(Dog a, Dog b) { return a.name.compareTo(b.name); } } public static Comparator<Dog> getNameComparator() { return new NameComparator(); } } import java.util.Comparator; public class DogLauncher { public static void main(String[] args) { ... Comparator<Dog> nc = new Dog.getNameComparator(); if (nc.compare(d1, d3) > 0) { d1.bark(); } else { d2.bark(); } } }

Comparable and Comparator Summary

Open Note in New Page

Lecture11.md

Lecture 11: Exceptions, Iterators, Object Methods

9/21/2020

Lists and Sets in Java

Lists

List61B<Integer> L = new AList<>(); L.addLast(5); L.addLast(10); L.addLast(15); L.print();
java.util.List<Integer> L = new java.util.ArrayList<>(); L.add(5); L.add(10); L.add(15); System.out.println(L);

Lists in Real Java Code

import java.util.List; import java.util.ArrayList; List<Integer> L = new ArrayList<>();

Sets in Java and Python

Set<String> S = new HashSet<>(); S.add("Tokyo"); S.add("Beijing"); S.add("Lagos"); S.add("Sao Paulo"); Sysetme.out.println(S.contains("Tokyo"));

ArraySet

Goals

ArraySet (Basic Implementation)

public class ArraySet<T> { private T[] items; private int size; public ArraySet() { items = (T[]) new Object[100]; size = 0; } public boolean contains(T x) { for (int i = 0; i < size; i += 1) { if (e.equals(items[i])) { return true; } } return false; } public void add(T x) { if (contains(x)) { return; } items[size] = x; size += 1; } public int size() { return size; } }

Exceptions

Exceptions

public class ArraySet<T> { ... public void add(T x) { if (x == null) { throw new IllegalArgumentException("You can't add null to an ArraySet"); } if (contains(x)) { return; } items[size] = x; size += 1; } ... }

Explicit Exceptions

Iteration

The Enhanced For Loop

for (int i : javaset) { System.out.println(i); }

How Iteration Really Works

ArraySet<Integer> = new ArraySet<>(); Iterator<Integer> seer = aset.iterator(); while (seer.hasNext()) { int i = seer.next(); System.out.println(i); }

Support Ugly Iteration in ArraySets

public class ArraySet<T> implements Iterable<T> { ... public Iterator<T> iterator() { return new ArraySetIterator(); } private class ArraySetIterator implements Iterator<T> { private int wizPos; public ArraySetIterator() { wizPos = 0; } public boolean hasNext() { return wizPos < size; } public T next() { T returnItem = items[wizPos]; wizPos += 1; return returnItem; } } }

The Enhanced For Loop

public interface Iterable<T> { Iterator<T> iterator(); } public class ArraySet<T> implements Iterable<T> { ... public Iterator<T> iterator() { return new ArraySetIterator(); } private class ArraySetIterator implements Iterator<T> { private int wizPos; public ArraySetIterator() { wizPos = 0; } public boolean hasNext() { return wizPos < size; } public T next() { T returnItem = items[wizPos]; wizPos += 1; return returnItem; } } }

The Iterable Interface

Iteration Summary

Object Methods: Equals and toString()

Objects

toString()

ArraySet toString

public class ArraySet<T> implements Iterable<T> { ... @Override public String toString() { String returnString = "{"; for (int i = 0; i < size - 1; i += 1) { returnString += item.toString(); return String += ", "; } returnString += items[size - 1]; returnString += "}"; return returnString; } }

ArrayMap toString

public class ArraySet<T> implements Iterable<T> { ... @Override public String toString() { StringBuilder returnSB = new StringBuilder("{"); for (int i = 0; i < size - 1; i += 1) { returnSB.append(items[i].toString()); returnSB.append(", "); } returnS.append(items[size - 1]); returnString.append("}"); return returnSB.toString(); } }

Equals vs. ==

Set<Integer> javaset = Set.of(5, 23, 42); Set<Integer> javaset2 = Set.of(5, 23, 42); System.out.println(javaset == javaset2); // Prints false
Set<Integer> javaset = Set.of(5, 23, 42); Set<Integer> javaset2 = Set.of(5, 23, 42); System.out.println(javaset.equals(javaset2)); // Prints true

The Default Implementation of Equals

public class ArraySet<T> implements Iterable<T> { ... @Override public boolean equals(Object other) { ArraySet<T> o = (ArraySet<T>) other; if (o.size() != this.size()) { return false; } for (T item: this) { if (o.contains(item)) { return false; } } return true; } }
public class ArraySet<T> implements Iterable<T> { ... @Override public boolean equals(Object other) { if (other == null) { return false; } if (other.getClass() != this.getClass()) { return false; } ArraySet<T> o = (ArraySet<T>) other; if (o.size() != this.size()) { return false; } for (T item: this) { if (o.contains(item)) { return false; } } return true; } }
public class ArraySet<T> implements Iterable<T> { ... @Override public boolean equals(Object other) { if (this == other) { return true; } if (other == null) { return false; } if (other.getClass() != this.getClass()) { return false; } ArraySet<T> o = (ArraySet<T>) other; if (o.size() != this.size()) { return false; } for (T item: this) { if (o.contains(item)) { return false; } } return true; } }

Summary

Summary

Open Note in New Page

Lecture13.md

Lecture 13: Asymptotics I

9/26/2020

61B: Writing Efficient Programs

Example of Algorithm Cost

Characterization 1 Clock Time

How Do I Runtime Characterization?

Techniques for Measuring Computational Cost

Techniques for Measuring Computational Cost

Why Scaling Matters

Comparing Algorithms

Asymptotic Behavior

Parabolas vs. Lines

Scaling Across Many Domains

Worst Case Orders of Growth

Intuitive Simplification 1: Consider Only the Worst Case

Intuitive Simplification 2: Restrict Attention to One Operation

Intuitive Simplification 3: Eliminate low order terms

Intuitive Simplification 4: Eliminate multiplicative constants

Simplification Summary

Simplified Analysis

Simplified Analysis Process

Analysis of Nested For Loops (Based on Exact Count)

int N = A.length; for (int i = 0; i < N; i += 1) { for (int j = i + 1; j < N; j += 1) { if (A[9] == A[j]) { return true; } } } return false

AnLysis of Nested For Loops (Simpler Geometric Argument)

Formalizing Order of Growth

Big-Theta: Formal Definition

Big-Theta and Runtime AnLysis

Big O Notation

Big O


Big Theta vs. Big O

Summary

Summary From Discussion

Aymptotics

Open Note in New Page

Lecture14.md

Lecture 14: Disjoint Sets

9/28/2020

Intro to Disjoint Sets

Meta-goals of the Coming Lectures: Data Structure Refinement

The Disjoint Sets Data Structure

Disjoint Sets on Integers

The Disjoint Sets Interface

public interface DisjointSets { /** Connects two items P and Q */ void connect(int p, int q); /** Checks to see if two items are connected */ boolean isConnected(int p, int q); }

The Naive Approach

A Better Approach: Connected Components

Quick Find

Performance Summary

My Approach: Just use a list of integers

Quick Union

Improving the Connect Operation

Set Union Using Rooted-Tree Representation

Weighted Quick Union

Weighted Quick Union

Implementing WeightedQuickUnion

Weighted Quick Union Performance

Performance Summary

Why Weights Instead of Heights?

Path Compression (CS 170 Spoiler) (Can we do better?)

What We've Achieved

CS 170 Spoiler: Path Compression: A Clever Idea

A Summary of Our Iterative Design Process

Summary From Discussion

Disjoint Sets

Open Note in New Page

Lecture15.md

Lecture 15: Asymptotics II

9/30/2020

Loops

Loops Example 1: Based on Exact Count

int N = A.length; for (int i = 0; i < N; i += 1) for (int j = i + 1; j < N; j += 1) if (A[i] == A[j]) return true; return false;

Loops Example 2

int N = A.length; for (int i = 1; i < N; i = i * 2) for (int j = 0; j < i; j += 1) System.out.println("hello"); int ZUG = 1 + 1; return false;

No Magic Shortcut

Repeat After Me...

Recursion

Recursion (Intuitive)

public static int f3(int n) { if (n <= 1) return 1; return f3(n-1) + f3(n-1); }

Recursion and Exact Counting

Recursion and Recurrence Relations

Binary Search Intuitive

Binary Search Exact Count

Binary Search (using Recurrence Relations)

Log Time is Really Terribly Fast

Merge Sort

Selection Sort: A Prelude to Mergesort

The Merge Operation

Using Merge to Speed Up the Sorting Process

Two Merge Layers

Example 5: Mergesort

Mergesort Order of Growth

Linear vs. Linearithmic (N log N) vs Quadratic

Summary

Open Note in New Page

Lecture16.md

Lecture 16: ADTs, Sets, Maps, Binary Search Trees

10/2/2020

Abstract Data Types

Abstract Data Types (ADT)

Another example of an ADT: The Stack

GrabBag ADT

Abstract Data Types in Java

Collections

Java Libraries

Binary Search Trees

AnLysis of an OrderedLinkedListSet

Optimization: Change the Entry Point

BST Definitions

Tree

Rooted Trees and Rooted Binary Trees

Binary Search Trees

Finding a searchKey in a BST

static BST find(BST T, key sk) { if (T == null) return null; if (sk.equals(T.key)) return T; else if (sk < T.key) return find(T.left, sk); else return find(T.right, sk); }

BSTs

BST Operations: Insert

Inserting a new key into a BST

static BST insert(BST T, Key ik) { if (T == null) return new BST(ik); if (ik < T.key) T.left = insert(T.left, ik); else if (ik > T.key) T.right = insert(T.right, ik); return T; }

BST Operation: Delete

Deleting from a BST

Case 1: Deleting from a BST: Key with no Children

Case 2: Deleting from a BST: Key with one Child

Case 3: Deleting from a BST: Deletion with two Children

Sets vs. Maps, Summary

Sets vs. Maps

Summary

BST Implementation Tips

Tips for BST Lab

CSM Review

interface List<E> { boolean add(E element); void add(int index, E element); E get(int index); int size(); }
interface Map<K, V> { V put(K key, V value); V get(K key); boolean containsKey(Object key); Set<K> keySet(); }
interface Set<E> { boolean add(E element); boolean contains(Object object); int size(); boolean remove(Object object); }

Open Note in New Page

Lecture17.md

Lecture 17: B-Trees (2-3, 2-3-4 Trees)

10/5/2020

BST Tree Height

BST Tree Height

The Usefulness of Big O

Height, Depth, and Performance

Height and Depth

Height, Depth, and Runtime

Important Question: What about real world BSTs?

Randomized Trees: Mathematical Analysis

Good News and Bad News

B-trees / 2-3 trees / 2-3-4 trees

Avoiding Imbalance through Overstuffing

Revising Our Overstuffed Tree Approach: Moving Items Up

Revising Overstuffed Tree Approach: Node Splitting

add: Chain Reaction

What Happens if the root is too full?

Perfect Balance

THe Real Name for Splitting Trees is "B Trees"

B-tree Bushiness Invariants

Exercise

B-Tree Invariants

B-Tree Runtime Analysis

Height of a B-Tree with Limit L

Runtime for contains

Summary

Summary

Open Note in New Page

Lecture18.md

Lecture 18: Red Black Trees

10/7/2020

The Bad News

BST Structure and Tree Rotation

BSTs

Tree Rotation Definition

Rotation for Balance

Rotation: An Alternate Approach to Balance

Red-Black Trees

Search Trees

Representing a 2-3 Tree as a BST

Left-Leaning Red Black Binary Search Tree (LLRB)

Red Black Tree Properties

Left-Leaning Red Black Binary Search Tree (LLRB)

Left-Leaning Red Black Binary Search Tree (LLRB) Properties

LLRB Construction

Maintaining 1-1 Correspondence Through Rotations

The 1-1 Mapping

Design Task 1: Insertion Color

Design Task 2: Insertion on the Right

New Rule: Representation of Temporary 4-Nodes

Design Task 3: Double insertion on the left

Design Task 4: Splitting Temporary 4-nodes

That's it!

LLRB Runtime and Implementation

LLRB Runtime

LLRB Implementation

Search Tree Summary

Search Tree

CSM Review

B-Trees

2-3 Trees

2-3-4 Trees

Traversals

Rotating Nodes

Left-Leaning Red Black Trees

Tree Traversals

Open Note in New Page

Lecture19.md

Lecture 19: Multidimensional Data

10/9/2020

Range-Finding and Nearest

Search Trees

Expanding the Power of our Set

Implementing Fancier Set Operations with a BST

Sets and Maps on 2D Data

Multi-Dimensional Data

Motivation: 2D Range Finding and Nearest Neighbors

QuadTrees

The QuadTree

QuadTrees

Higher Dimensional Data

3D Data

Even Higher Dimensional Space

K-d Trees

K-d Trees and Nearest Neighbor

Nearest Pseudocode

Uniform Partitioning

Uniform Partitioning

Uniform vs. Hierarchical Partitioning

Uniform Partitioning vs. Quadtrees and Kd-Trees

Summary and Applications

Multi-Dimensional Data Summary

Open Note in New Page

Lecture20.md

Lecture 20: Hash Tables

10/12/2020

Data Indexed Arrays

Limits of Search Tree Based Sets

Using Data as an Index

public class DataIndexedIntegerSet { private boolean[] present; public DataIndexedIntegerSet() { present = new boolean[2000000000]; } public add(int i) { present[i] = true; } public contains(int i) { return present[i]; } }

DataIndexedEnglishWordSet

Generalizing the DataIndexedIntegerSet Idea

Avoiding Collisions

THe Decimal Number System vs. Our Own System for Strings

Uniqueness

public class DataIndexedEnglishWordSet { private boolean[] present; public DataIndexedEnglishWordSet() { present = new boolean[2000000000]; } public add(String s) { present[englishToInt(s)] = true; } public contains(String s) { return present[englishToInt(s)]; } }

DataIndexedStringSet

DataIndexedStringSet

ASCII Characters

Implementing asciiToInt

Going Beyond ASCII

Example: Computing Unique Representations of Chinese

Integer Overflow and Hash Codes

Major Problem: Integer Overflow

Consequence of Overflow: Collisions

Hash Codes and the Pigeonhole Principle

Two Fundamental Challenges

Hash Tables: Handling Collisions

Resolving Ambiguity

The Separate Chaining Data Indexed Array

Separate Chaining Performance

Saving Memory Using Separate Chaining

The Hash Table

Hash Table Performance

Hash Table Runtime

Improving the Hash Table

Hash Table Runtime

Resizing Hash Table Runtime

Has Table Runtime

Regarding Even Distribution

Hash Tables in Java

The Ubiquity of Hash Tables

Objects

Examples of Real Java HashCodes

"a".hashCode() // 97 "bee".hashCode() // 97410

Using Negative hash codes

-1 % 4 // -1 Math.floorMod(-1, 4) // 3

Hash Tables in Java

Two Important Warnings When Using HashMaps/HashSets

Good HashCodes

What Makes a good hashCode()?

Hashbrowns and Hash Codes

Example hasCode Function

@Override public int hasCode() { int h = cachedHashValue; if (h == 0 && this.length() > 0) { for (int i = 0; i < this.length; i++) { h = 31 * h + this.charAt(i); } cachedHasValue = h; } return h; }

Example: Choosing a Base

Typical Base

Hashbrowns and Hash Codes

Example: Hashing a Collection

@Override public int hashCode() { int hashCode = 1; for (Object o : this) { hashCode = hashCode * 31; // elevate/smear the current hash code hashCode = hashCode + o.hashCode(); // add new item's hash code } return hashCode }

Example: Hashing a Recursive Data Structure

@Override public int hashCode() { if (this.value == null) { return 0; } return this.value.hashCode() + 31 * this.left.hashCode() + 31 * 31 * this.right.hashCode(); }

Summary

Hash Tables in Java

Open Note in New Page

Lecture21.md

Lecture 21: Heaps and PQs

10/14/2020

The Priority Queue Interface

The Priority Queue Interface

/** (Min) Priority Queue: Allowing tracking and removal of the * smallest item in a priority queue */ public interface MinQP<Item> { // Adds the item to the priority queue public void add(Item x); // Returns the smallest item in the priority queue public Item getSmallest(); // Removes the smallest item from the priority queue public Item removeSmallest(); // Returns the size of the priority queue public int size(); }

Usage example: Unharmonious Text

Naive Implementation: Store and Sort

Better Implementation: Track the M Best

How Would we Implement a MinPQ?

Heaps

Introducing the Heap

What Good are Heaps?

How Do We Add to a Heap?

Heap Operations Summary

Tree Representations

How do we represent a tree in Java?

public class Tree1A<Key> { Key k; Tree1A left; Tree1A middle; Tree1A right; }
public class Tree1B<Key> { Key k; Tree1B[] children; ... }
// Sibling tree public class Tree1C<Key> { // Nodes at the same level point to each other's siblings Key k; Tree1C favoredChild; Tree1C sibling; }
public class Tree2<Key> { Key[] keys; int[] parents; ... }

public class Tree3<Key> { Key[] keys; }

A Deep Look at Approach 3

public void swim(int k) { if (keys[parent(k)] > keys[k]) { swap(k, parent(k)); swim(parent(k)); } }
public int parent(int k) { if (k == 0) { return 0; } return (k - 1) / 2; }

Approach 3B (book implementation): Leaving One Empty Spot in the Front

Heap Implementation of a Priority Queue

Some Implementation Questions

Data Structures Summary

The Search Problem

Search Data Structures (The particularly abstract ones)

Data Structures

Summary

Discussion Summary: Heaps

Open Note in New Page

Lecture22.md

Prefix Operations and Tries

10/16/2020

Tries

Abstract Data Types vs. Specific Implementations

BST and Hash Table Set Runtimes

Special Case 1: Character Keyed Map

public class DataIndexedCharMap<V> { private V[] items; public DataIndexedCharMap(int R) { items = (V[]) new Object[R]; } public void put(char c, V val) { items[c] = val; } public V get(char c) { return items[c]; } }

Special Case 2: String Keyed Map

Sets of Strings

Tries: Search Hits and Misses

Trie Maps

Tries

Trie Implementation and Performance

Very Basic Trie Implementation

public class TrieSet { private static final int R = 128; // ASCII private Node root; // root of trie private static class Node { private char ch; // Actually don't need this variable private boolean isKey; private DataIndexedCharMap next; private Node(char c, boolean b, int R) { ch = c; isKey = b; next = new DataIndexedCharMap<Node>(R); } } }

Trie Performance in Terms of N

Alternate Child Tracking Strategies

DataIndexedCharMap Trie

Alternate Idea #1: The Hash-Table Based Trie

Alternate Idea #2: The BST-Based Trie

The Three Trie Implementations

Performance of the DataIndexedCharMap, BST, and Hash Table

Trie Performance in Terms of N

Trie String Operations

String Specific Operations

Collecting Trie Keys

Usages of Tries

Autocomplete

The Autocomplete Problem

A More Efficient Autocomplete

Even More Efficient Autocomplete

Trie Summary

Tries

Domain Specific Sets and Maps

Discussion Summary: Tries

Open Note in New Page

Lecture23.md

Lecture 23: Tree and Graph Traversals

10/19/2020

Trees and Traversals

Tree Definition

Rooted Trees Definition

Trees

Example: File Tree System

Tree Traversal Orderings

Depth First Traversals

preOrder(BSTNode x) { if (x == null) return; print(x.key) preOrder(x.left) preOrder(x.right) }
inOrder(BSTNode x) { if (x == null) return; inOrder(x.left) print(x.key) inOrder(x.right) }
postOrder(BSTNode x) { if (x == null) return; postOrder(x.left) postOrder(x.right) print(x.key) }

A Useful Visual Trick (for Humans, not algorithms)

What Good are all These Traversals

Graphs

Trees and Hierarchical Relationships

Graph Definition

Graph Type

Graph Terminology

Graph Problems

Graph Queries

Graph Queries More Theoretically

Graph Problem Difficulty

Depth-First Traversal

s-t Connectivity

Depth First Traversal

DepthFirstPaths

Tree Vs. Graph Traversals

Tree Traversals

Graph Traversal

Summary

Summary

Open Note in New Page

Lecture24.md

Lecture 24: Graph Traversals and Implementations

10/21/2020

Note

Graph Traversals

Shortest Path Problem

BreadthFirstSearch for Google Maps

Graph API

Graph Representations

Graph API Decision #1: Integer Vertices

Graph API

public class Graph { public Graph(int V); // Create empty graph with v vertices public void addEdge(int v, int w); // add an edge v-w Iterable<Integer> adj(int v); // vertices adjacent to v int V(); // number of vertices int E(); // number of edges }
/** degree of vertex v in graph G */ public static int degree(Graph G, int v) { int degree = 0; for (int w : G.adj(v)) { degree += 1; } return degree; }
/** Prints out all the edges in a graph */ public static void print(Graph G) { for (int v = 0; v < G.V(); v += 1) { for (int w : G.adj(v)) { System.out.println(v + "-" + w); } } }

Graph API and DepthFirstPaths

Graph Representation and Graph Algorithm Runtimes

Graph Representations

Graph Printing Runtime

More Graph Representations

Graph Printing Runtime

Barebones Undirected Graph Implementation

public class Graph { private final int V; private List<Integer>[] adj; public Graph(int V) { this.V = V; adj = (List<Integer>[]) new ArrayList[V]; for (int v = 0; v < V; v++) { adj[v] = new ArrayList<Integer>(); } } public void addEdge(int v, int w) { adj[v].add(w); adj[w].add(v); } public Iterable<Integer> adj(int v) { return adj[v]; } }

Graph Traversal Implementations and Runtime

Depth Fist Search Implementation

public class Paths { public Paths(Graph G, int s); // Find all paths from G boolean hasPathTo(int v); // is there a path from s to v? Iterable<Integer> pathTo(int v); // path from s to v (if any) }

DepthFirstPaths Demo

DepthFirstPaths, Recursive Implementation

public class DepthFirstPaths { private boolean[] marked; private int[] edgeTo; private int s; public DepthFirstPaths(Graph G, int s) { ... dfs(G, s); } public void dfs(Graph G, int v) { marked[v] = true; for (int w : G.adj(v)) { if (!marked[w]) { edgeTo[w] = v; dfs(G, w); } } } public boolean hasPathTo(int v) { return marked[v]; } public Iterable<Integer> pathTo(int v) { if (!hasPathTo(v)) return null; List<Integer> path = new ArrayList<>(); for (int x = v; x !=s; x = edgeTo[x]) { path.add(x); } path.add(s); Collections.reverse(path); return path; } }

Runtime for DepthFirst Paths

Runtime for DepthFirstPaths

BreadthFirstPaths Implementation

public class BreadthFirstPaths { private boolean[] marked; private int[] edgeTo; ... private void bfs(Graph G, int s) { Queue<Integer> fringe = new Queue<Integer>(); fringe.enqueue(s); marked[s] = true; while (!fringe.isEmpty()) { int v = fringe.dequeue(); for (int w : G.adj(v)) { if (!marked[w]) { fringe.enqueue(w); marked[w] = true; edgeTo[w] = v; } } } } }

Layers of Abstraction

Clients and Our Graph API

Runtime for DepthFirstPaths

Summary

Summary

Discussion Review

Graphs

Graph Representations

Graph Searches

Dijkstra's Algorithm

A*

Open Note in New Page

Lecture25.md

Lecture 25: Shortest Paths

10/23/2020

Graph Problems

BFS vs. DFS for Path Finding

Breadth FirstSearch for Google Maps

Dijkstra's Algorithm

Single Source Single Target Shortest Paths

Problem: Single Source Shortest Paths

Edge Count

Creating an Algorithm

Dijkstra's Algorithm

Dijkstra's Correctness and Runtime

Dijkstra's Algorithm Pseudocode

Guaranteed Optimality

Negative Edges

Dijkstra's Algorithm Runtime

A*

Single Target Dijkstra's

The Problem with Dijkstra's

How can we do better?

Introducing A*

A* Heuristic Example

A* Heuristics (Not covered in this class)

Heuristics and Correctness

Consistency and Admissibility (Beyond scope)

Summary

Summary: Shortest Paths Problems

Open Note in New Page

Lecture26.md

Lecture 26: Minimum Spanning Trees

10/29/2020

Spanning Trees

Spanning Trees

MST Applications

MST vs. SPT

A Useful Tool for Finding the MST: Cut Property

Cut Property Proof

Generic MST Finding Algorithm

Prim's Algorithm

Prim's Algorithm

Prim's Algorithm Implementation

Prim's Demo

Prim's vs. Dijkstra's

Prim's Implementation (Psuedocode)

public class PrimMST { public PrimMST(EdgeWeightedGraph G) { edgeTo = new Edge[G.V()]; distTo = new double[G.V()]; marked = new boolean[G.V()]; fringe = new SpecialPQ<Double>(G.V()); distTo[s] = 0.0; setDistancesToInfinityExceptS(s); /* Fringe is ordered by distTo tree. Must be a specialPQ like Dijkstra's */ insertAllVertices(fringe); /* Get vertices in order of distance from tree */ while (!fringe.isEmpty()) { // Get vertex closest to tree that is unvisited int v = fringe.delMin(); // Scan means to consider all of a vertex's outgoing edges scan(G, v) } } private void scan(EdgeWeightedGraph G, int v) { marked[v] = true; // Vertex is closest, so add to MST for (Edge e : G.adj(v)) { int w = e.other(v); /* Already in MST, so go to next edge */ if (marked[w]) {continue;} /* Better path to a particular vertex found, so update current best known for that vertex */ if (e.weight() < distTo[w]) { distTo[w] = e.weight(); edgeTo[w] = e; pq.decreasePriority(w, distTo[w]); } } } }

Prim's Runtime

Kruskal's Algorithm

Kruskal's Demo

Kruskal's Algorithm

Kruskal's Implementation (Psueocode)

public class KruskalMST { private List<edge> mst = new ArrayList<Edge>(); public KruskalMST(EdgeWeightedGraph G) { MinPQ<Edge> pq = new MinPQ<Edge>(); for (Edge e : G.edges()) { pq.insert(e); } WeightedQuickUnionPC uf = new WeightedQuickUnionPC(G.V()); while(!pq.isEmpty() && mst.size() < G.V() - 1) { Edge e = pq.delMin(); int v = e.from(); int w = e.to(); if (!uf.connected(v, w)) { uf.union(v, w); mst.add(e); } } } }

Kruskal's Runtime

Shortest Paths and MSt algorithms Summary

170 Spoiler: State of the Art Compare-Based MST Algorithms

CSM Summary: Graph Algorithms

Depth First Search (DFS)

Breadth First Search (BFS)

Shortest Paths Tree vs Minimum Spanning Tree

Shortest Paths Tree Algorithms

Dijkstra's/A*/Prim's Runtime

Cut Property

MST Algorithms

Open Note in New Page

Lecture27.md

Lecture 27: Software Engineering I

10/30/2020

Motivation

Complexity Defined

The Power of Software

Complexity, the Enemy

Dealing with Complexity

The Nature of Complxity

Complexity

Complexity and Importance

Symptoms and Causes of Complexity

Symptoms of Complexity

Obvious Systems

Complexity Comes Slowly

Strategic vs. Tactical Programming

Tactical Programming

Strategic Programming

Suggestions for Strategic Programming

Strategic Programming is Very Hard

Open Note in New Page

Lecture28.md

Lecture 28: Reductions and Decomposition

10/31/2020

Topological Sorting

Topological Sort

Solution

Topological Sort

Directed Acyclic Graphs

Shortest Paths on DAGs

Challenge

The DAG SPT Algorithm: Relax in Topological Order

Longest Paths

The Longest Paths Problem

The Longest Paths Problem on DAGs

Reduction (170 Preview)

DAG Longest Paths and Reduction

Reduction Analogy

Reduction Definition (Informal)

Reduction is More than Sign Flipping

The Independent Set Problem

THe 3SAT Problem

3SAT Reduces to Independent Set

Reduction

Reductions and Decomposition

Open Note in New Page

Lecture29.md

Lecture 29: Basic Sorts

11/4/2020

Sorting Definitions

Java Note

import java.util.Comparator; public class LengthComparator implements Comparator<String> { public int compare(String x, String b) { return x.length() - b.length(); } }

Sorting: An Alternate Viewpoint

Performance Definitions

Selection Sort and Heapsort

Selection Sort

Naive Heapsort: Leveraging a Max-Oriented Heap

In-place Heapsort

Mergesort

Mergesort

Insertion Sort

Insertion Sort

In-place Insertion Sort

Observation: Insertion Sort on Almost Sorted Arrays

Insertion Sort Sweet Spots

Sorts Table

Open Note in New Page

Lecture30.md

Lecture 30: Quicksort

11/4/2020

Backstory, Partitioning

Sorting So Far

Context for Quicksort's Invention

The Core Idea of Tony's Sort: Partitioning

Interview Question

Simplest (but not fastest) Answer: 3 Scan Approach

Quicksort

Partition Sort, a.k.a. Quicksort

Quicksort

Quicksort Runtime

Best Case: Pivot Always Lands in the Middle

Worst Case: Pivot Always Lands at Beginning of Array

Quicksort Performance

(Intuitive) Argument #1 for Average Runtime: 10% Case

(Intuitive) Argument #2: Quicksort is BST Sort

Empirical Quicksort Runtimes

Quicksort Performance

Sorting Summary (so far)

Avoiding the Quicksort Worst Case

Quicksort Performance

Avoiding the Worst Case

Open Note in New Page

Lecture31.md

Lecture 31: Software Engineering 2

11/6/2020

Build Your World

Part 1: World Generation

Part 2: Interactivity

Ousterhout's Take on Complexity

Modular Design

Hiding Complexity

Modular Design

Interface vs. Implementation

Interface

Modules Should be Deep

Information Hiding

Information Leakage

Temporal Decomposition

BYOW Suggestions

Teamwork

Project 3

Teamwork

Individual Intelligence

Group Intelligence

Teamwork and Project 3

Reflexivity

Feedback is Hard: Negativity

Feedback is Hard: Can Seem Like a Waste of Time

Feedback is Hard: Coming Up With Feedback is Tough

Team Reflection

Open Note in New Page

Lecture32.md

Lecture 32: More Quick Sort, Sorting Summary

11/10/2020

Partition Sort a.k.a. Quicksort

Avoiding the Worst Case

Philosophy 1: Randomness (Preferred Approach)

Philosophy 2a: Smarter Pivot Selection (constant time pivot pick)

Philosophy 2b: Smarter Pivot Selection (linear time pivot pick)

Philosophy 3: Introspection

Sorting Summary (so far)

Quicksort Flavors

Tony Hoare's In-place Partitioning Scheme

What if we don't want randomness?

Median Identification

Quick Select

The Selection Problem

Quick Select

Worst Case Performance of Quick Select

Expected Performance

Quicksort with Quickselect

Stability, Adaptiveness, Optimization

Other Desirable Sorting Properties: Stability

Sorting Stability

Stability

Optimizing Sorts

Arrays.sort

Sorting Summary

Sorting Landscape

Sorting vs Searching

Open Note in New Page

Lecture33.md

Lecture 33: Software Engineering III - Your Life

11/13/2020

Overview

Workplace Preference

The Ledger of Harms

Concerns Expressed by Tech Leaders

Hug's Thoughts

The Center for Humane Technology and the Ledger of Harms

The Ledger of Harms

Your Life

The Power of Software

The Limiting Reagent

Steering the Course

TIme

Open Note in New Page

Lecture34.md

Lecture 34: Sorting and Algorithmic Bounds

11/16/2020

Sorting

Sorts Summary

Math Problems out of Nowhere

A Math Problem out of Nowhere

Another Math Problem

Last Math Problem

Omega and Theta

Theoretical Bounds on Sorting

Sorting

The Game of Puppy, Cat, Dog

Puppy, Cat, Dog - A Graphical Picture of N = 3

The Game of Puppy, Cat, Dog

Generalized Puppy, Cat, Dog

Generalizing Puppy, Cat, Dog

Sorting, Puppies, Cats, and Dogs

Sorting Lower Bound

Optimality

Open Note in New Page

Lecture35.md

Lecture 35: Counting Sort and Radix Sorts

11/18/2020

Comparison Based Sorting

Example 1: Sleep Sort (for sorting integers) (not actually good)

Example 2: Counting Sort: Exploiting Space Instead of Time

Generalizing Counting Sort

Implementing Counting Sort with Counting Arrays

Counting Sort Runtime

Counting Sort vs. Quicksort

Counting Sort Runtime Analysis

Counting Sort vs. Quicksort

Sort Summary

LSD Radix Sort

Radix Sort

LSD (Least Significant Digit) Sort

LSD Runtime

Non-equal Key Lengths

Sorting Summary

MSD Radix Sort

MSD (Most Significant Digit) Radix Sort

Runtime of MSD

Sorting Runtime Analysis

Open Note in New Page

Lecture36.md

Lecture 36: Radix vs. Comparison Sorting, Sorting and Data Structures Conclusion

11/20/2020

Intuitive: Radix Sort vs. Comparison Sorting

Merge Sort Runtime

LSD vs. Merge Sort

Cost Model: Radix Sort vs. Comparison Sorting

Alternate Approach: Picking a Cost Model

MSD vs. Mergesort

MSD vs. Mergesort Character Examinations

Empirical Study: Radix Sort vs. Comparison Sorting

Computational Experiment Results

An Unexpected Factor: The Just-In-Time Compiler

Rerunning Our Empirical Study Without JIT

Computational Experiments Results with JIT disabled

So Which is Better? MSD or MergeSort?

Bottom Line: Algorithms Can be Hard to Compare

Radix Sorting Integers (61C Preview)

Linear Time Sorting

LSD Radix Sort on Integers

Relationship Between Base and Max # Digits

Another Counting Sort

Sorting Summary

Sorting Landscape

Sorting vs. Searching

Open Note in New Page

Lecture37.md

Lecture 37: Compression

11/30/2020

Zip Files, How Do They Work?

Compression Model #1: Algorithms Operating on Bits

Prefix Free Codes

Increasing Optimality of Coding

More Code: Mapping Alphanumeric Symbols to Codewords

Prefix-Free Codes [Example 1]

Prefix-Free Codes [Example 2]

Prefix Free Code Design

Shannon Fano Codes (Extra)

Code Calculation Approach #1 (Shannon-Fano Coding)

Huffman Coding

Code Calculation Approach #2: Huffman Coding

Huffman Coding Data Structures

Prefix-Free Codes

Huffman Coding in Practice

Huffman Compression

Huffman Compression Steps

Huffman Decompression Steps

Huffman Coding Summary

Compression Theory

Compression Algorithms (General)

Comparing Compression Algorithms

Universal Compression: An Impossible Idea

A Sneaky Situation

Compression Model #2: Self-Extracting Bits