Comparing changes

1.0.0 2.0.0
75 commits 55 files changed

Commits

64343a3 Run clang formatter mo khan 2020-08-17 01:32:46
5e11cbb Rebalance tree after each insert mo khan 2020-08-17 01:24:20
f531d9c Detect scapegoat and rebalance the tree mo khan 2020-08-17 01:10:19
baebca6 Fix mistake in program profile mo khan 2020-08-17 00:19:07
b8e927b Calculate the size of a binary tree mo khan 2020-08-16 23:26:38
b9843aa Update profile for question 5 mo khan 2020-08-16 22:44:54
512074d Complete writeup for problem 4 mo khan 2020-08-16 20:03:09
fabd1c7 Add writeup for question 3 mo khan 2020-08-16 19:53:11
8b865ca Complete program profile for question 2 mo khan 2020-08-16 19:08:11
ed92840 Complete write-up for 02/01 mo khan 2020-08-16 18:54:26
76139d9 Start program profiles for assignment 2 mo khan 2020-08-16 18:36:31
fddc2c7 Document code for the marks mo khan 2020-08-16 00:04:31
3d811c6 Remove curly braces mo khan 2020-08-10 00:23:40
082e48d Run clang fmt mo khan 2020-08-10 00:21:26
9eca43f Use stack to do post order traversal mo khan 2020-08-10 00:09:57
86db346 Cache pre order traversal of tree mo khan 2020-08-09 23:49:54
4c99154 inline increment mo khan 2020-08-09 22:57:59
b15ec4d Use Stack to do in order traversal mo khan 2020-08-09 22:53:41
86c7705 Add test to suite mo khan 2020-08-09 21:47:49
7c4da6d Allow storing void* on Stack mo khan 2020-08-09 21:47:03
ce1f797 Start notes on open addressing mo khan 2020-08-09 21:37:11
5d99a9a Start to build a stack mo khan 2020-08-09 21:32:19
27f7fa7 Add failing to test mo khan 2020-08-06 03:48:30
2fc19c9 Implement stack_pop mo khan 2020-08-06 03:42:35
8ebf2af Implement stack peek mo khan 2020-08-06 03:35:29
97628eb Start to build a stack mo khan 2020-08-06 03:30:37
10ccd7e Yet another btree mo khan 2020-08-06 02:40:15
f9f81dd Run clang fmt mo khan 2020-08-06 02:29:12
6dd7226 Print out binary tree mo khan 2020-08-05 01:58:26
08d2c8d format the codes mo khan 2020-07-13 01:25:15
b08b548 Add notes on Karp-Rabin algorithm mo khan 2020-08-04 03:18:31
f5303d4 Hashing with Chaining mo khan 2020-08-04 01:07:51
1a22ef1 Run clang formatter mo khan 2020-08-03 21:57:46
48c2554 Pretty print tuple in console mo khan 2020-08-03 21:56:50
8b6d6e4 Create program to display hash table mo khan 2020-08-03 21:49:36
3a79c28 Run clang code formatter mo khan 2020-08-03 21:31:24
bb8ead8 Enable test to produce hash collision mo khan 2020-08-03 20:51:44
ff6613d Store Tuples in the hash mo khan 2020-08-03 20:27:51
e291a2c Create tuple mo khan 2020-08-03 19:52:16
53434ee Write mini hash table in ruby mo khan 2020-08-03 19:42:14
39450f0 Build a usable list mo khan 2020-08-03 02:12:51
6e2d8e1 Start to handle collisions mo khan 2020-08-02 19:06:49
5629d8c pass value as **void mo khan 2020-08-02 18:32:55
db7f5fa Build a hacky hash table mo khan 2020-08-02 03:25:11
c042952 Start to build a hash table mo khan 2020-08-02 02:27:28
88f4bd7 Add notes on scapegoat tree mo khan 2020-07-19 19:29:22
930c6ec Perform a recursive insert into a btree mo khan 2020-07-19 19:10:22
72811b3 Start to work on inserting into a btree mo khan 2020-07-19 18:59:30
c502a6f Add program to demonstrate bst check mo khan 2020-07-19 18:23:18
40f2327 Remove prefix from private function mo khan 2020-07-19 18:14:22
6441d1b Start to test if a btree is a bst mo khan 2020-07-18 21:56:44
07b83ec Run code formatter mo khan 2020-07-12 21:59:14
01080ba Call destructor after each spec mo khan 2020-07-11 22:57:30
dce786c Rename function in header file as well mo khan 2020-07-11 22:45:26
b97a3ba Rename to preorder traversal mo khan 2020-07-11 22:44:33
1efedbd Start assignment 2 mo khan 2020-07-11 21:46:37
7875e6d Add make clean and exclude tarballs mo khan 2020-07-05 21:45:02
525b906 Add link to the course website mo khan 2020-07-05 21:30:31
20fcabd Add course description mo khan 2020-07-05 21:29:48
doc/mit-ocw/bst.md
@@ -0,0 +1,9 @@
+# Scheduling & Binary Search Trees
+
+* Airport with a single runway.
+* Reservations for future landings.
+* Reserve request specifies landing time t
+* Add `t` to the set `R` of landing times if no other landings are scheduled within `k` minutes.
+* Remove from set `R` after plane lands.
+* `|R| = n`
+* `O(lg n)` time where `n` is the size of the set.
doc/mit-ocw/hash.md
@@ -0,0 +1,226 @@
+# Hashing
+
+[video][mit-ocw]
+
+## Motivation
+
+* database
+* compilers and interpreters
+* network router
+* substring search
+* string commonalities
+* file/dir synchronization
+
+Direct Access table:
+
+  ----------
+0 |        |
+  ----------
+1 |        |
+  ----------
+2 |        |
+  ----------
+3 |        |
+  ----------
+4 |        |
+  ----------
+  | ...    |
+  ----------
+  | ...    |
+  ----------
+  | ...    |
+  ----------
+
+> Hash requires mapping to an integer.
+
+ideally:
+
+* prehash hash(x) == hash(y) only when x == y
+
+badness:
+
+1. keys may not be non negative integers
+1. gigantic memory hog
+
+hashing -> hatchet
+
+- reduce universe of all possible keys and reduce them down to some reasonable set of integers.
+- idea: m = theta(n)
+  - size of table proportial to size of # of things.
+
+    -----------
+0   | | | | | |
+    ----------
+1   |         |
+    ----------
+2   |         |
+    ----------
+3   |         |
+    ----------
+4   |         |
+    ----------
+    | ...     |
+    ----------
+    | ...     |
+    ----------
+m-1 | ...     |
+    ----------
+
+Collision: Multiple keys map to same slot in hash table.
+* h(ki) == h(kj) but ki <> kj
+* we can use chaining
+
+How to define?
+
+* function (h)
+* all keys map to `h = { 0, ..., m-1 }`
+
+Two ways to deal with collisions:
+
+* Chaining: store collisions as a list. (i.e. linked list)
+* Open addressing
+
+## Chaining
+
+    ----------
+0   |         | --> (item1) --> (item2) --> (nil)
+    ----------
+1   |         |
+    ----------
+2   |         |
+    ----------
+3   |         |
+    ----------
+4   |         |
+    ----------
+    | ...     |
+    ----------
+    | ...     |
+    ----------
+m-1 | ...     |
+    ----------
+
+Worst case:
+
+* theta(n) (i.e. all items have a collision)
+
+Simple uniform hashing:
+
+* Convenient for analysis.
+* each key is equally likely to be hashed to any slot of the table, independent of where other keys hashing.
+
+Analysis:
+
+* expected length of a chain for n keys, m slots.
+  * n/m == alpha == load factor
+  * O(1 + alpha)
+
+## Hash functions:
+
+1. division method:
+  * `h(k) == k mod m`
+  * works okay if `m` is prime and not close to power of 2 or power of 10.
+2. multiplication method:
+  * `h(k) = [(a*k) mod 2^w] >> (w - r)`
+3. Universal hasing:
+  * `h(k) = [(ak+b) mod p] mod m`
+    * `a`, `b` are random between 0 and `p-1`. p is a big prime number larger than the universe.
+    * `{0, ..,p-1}`
+  * worst case keys: k1 != k2
+    * `1/m`
+
+## How to choose m?
+
+* Want `m = theta(n)`
+  * `0(1)`
+
+Idea:
+
+> Start small; grow/shrink as necessary
+
+E.g.
+
+* If n > m: grow table
+
+* grow table:
+  * m -> m'
+    * make table of size `m'`
+    * build new hash function `h'`
+    * rehash
+      * for item in T:
+        * t:insert(item)
+    * `m' = 2m` table doubling
+
+Amortization:
+* operation takes `T(n) amortized`
+  * if `k` operations take <= `k*T(n)` time
+* spread out the high cost so you pay a little bit, but more often.
+* ~ Think of meaning `T(n)` on average, where average is taken over all the oeprations.
+
+> spread out the high cost so that it's cheap on average all the time.
+
+## Open Adressing
+
+* no chaining
+* use arrays
+* m: # of slots in the table
+* m >= # of elements
+
+```plaintext
+----------
+| item 1 |
+----------
+| item 2 |
+----------
+|        |
+----------
+|        |
+----------
+```
+
+probing: try to see if we can insert something into the hashtable.
+if we fail, we will compute a slightly different hash until we
+find an empty slot that we can insert into this table.
+
+Hash function specifies the order of slots to probe
+for a key. (for insert/search/delete)
+
+hash function `h(U, trial_count)`
+
+* U: universe of keys
+* trial_count: integer between 0 -> m-1
+
+`h(k,1)`
+arbitrary key k
+
+h(k,1), h(k,2), ... h(k, m-1)
+
+to be a permutation of 0,1 ... m-1
+
+```plaintext
+  ----------
+0 |        |
+  ----------
+1 |        |
+  ----------
+2 |        |
+  ----------
+3 |        |
+  ----------
+4 |        |
+  ----------
+5 |        |
+  ----------
+6 |        |
+  ----------
+7 |        |
+  ----------
+```
+
+* `insert(k,v)`: keep probing until an empty slot is found. insert item when found.
+* `search(k)`: As long as the slots encountered are occupied by keys != k. keep probing until you either encounter k or find an empty slot.
+
+## Cryptographic Hash
+
+
+[mit-ocw]: https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-006-introduction-to-algorithms-fall-2011/lecture-videos/lecture-8-hashing-with-chaining/
doc/mit-ocw/kr.md
@@ -0,0 +1,74 @@
+# Karp-Rabin string matching algorithm
+* https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-006-introduction-to-algorithms-fall-2011/lecture-videos/lecture-9-table-doubling-karp-rabin/
+
+* given two string `s` & `t`: does `s` occur as a substring of `t`?
+
+```plaintext
+t: [ | | | | | | | | | | | | | | | | ]
+s: [ | | | ]
+  s: [ | | | ]
+    s: [ | | | ]
+      s: [ | | | ]
+        s: [ | | | ]
+          s: [ | | | ]
+            s: [ | | | ]
+              s: [ | | | ]
+                s: [ | | | ]
+                  s: [ | | | ]
+                    s: [ | | | ]
+                      s: [ | | | ]
+                        s: [ | | | ]
+                          s: [ | | | ]
+```
+
+Time:
+  * `theta(|s| * |t| - |s|)
+  * `theta(|s| * |t|) # length of s * length of t
+
+Can we use hashing to get this down to linear time?
+
+* We are looking for `O(|s|+|t|)` length of `s` + `t` is better than `s` times `t`.
+
+Rolling hash ADT:
+
+* `r.append(c)`:
+  * add char.c to end of x
+* `r.skip(c)`:
+  * delete fist character of x (assuming it is c)
+
+
+* `r` maintains a string `x`
+  * `r()` hash value of x = `h(x)`
+
+```python
+for c in s: rs.append(c)
+for c in t[:len(s)]:
+  rt.append(c)
+if rs() == rt(): ...
+for i in range(len(s), len(t)):
+  rt.skip(t[i - len(s)]
+  rt.append(t[i])
+  if rs() == rt:
+    s == t[i-len(s) + 1: i + i]
+    if equal:
+      found match
+    else:
+      happens with probability <= 1/|s|
+```
+
+division method:
+* `h(k) = k mod m` where `m` is a random prime >= |s| (prime is greater than length of s)
+* treat string x as a multi digit number base is size of alphabet.
+  * ascii -> 256
+  * unicode -> x
+
+```python
+r.append(c):
+  u -> u * a + ord(c)
+  r -> r * a + ord(c) mod m
+
+r.skip():
+  u -> u - c * a^|u|-1
+```
+
+* https://www.youtube.com/watch?v=qQ8vS2btsxI
doc/unit/08/README.md
@@ -0,0 +1,27 @@
+# Chapter 8: Scapegoat Trees
+
+> when something goes wrong, the first thing people tend to do is find someone to blame (the scapegoat).
+
+A Scapegoat tree implements the Sorted Set, `SSet`, interface.
+The tree supports the operations:
+
+| operation | time complexity |
+| ------------- | ------------- |
+| `add()` | O(log n) |
+| `remove()` | O(log n) |
+| `find()` | O(log n) |
+
+Balanced by partial rebuilding operations.
+
+* keeps track of the number of nodes `n`.
+* keeps a counter, `q`, that maintains an upper-bound on the number of nodes.
+
+At all times, `n` and `q` obey the following inequalities:
+
+> q/2 <= n <= q
+
+credit schema: Each node stores a number of credits.
+
+## Resources
+
+* http://people.csail.mit.edu/rivest/pubs/GR93.pdf
src/02/01/binary_tree.c
@@ -0,0 +1,84 @@
+#include "binary_tree.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Initialize a new node for a Binary Tree.
+ *
+ * @param data the data to assign to the root of the tree.
+ * @return The root of the binary tree.
+ */
+Node *initialize(int data) {
+  Node *item = malloc(sizeof(Node));
+  item->data = data;
+  item->left = NULL;
+  item->right = NULL;
+  return item;
+}
+
+/*
+ * Traverses a binary tree using the traversal algorithm specified.
+ * Time: O(n)
+ * Space: O(n) for each recursive stack frame
+ *
+ * @param node The root of the binary tree
+ * @param vistior A callback function to invoke on each node during the tree
+ * traversal
+ * @param traversal Specifies what type of traversal to perform
+ */
+void traverse(Node *node, Visitor visitor, enum Traversal traversal) {
+  if (!node)
+    return;
+
+  switch (traversal) {
+  case PREORDER:
+    visitor(node);
+    traverse(node->left, visitor, traversal);
+    traverse(node->right, visitor, traversal);
+    break;
+  case INORDER:
+    traverse(node->left, visitor, traversal);
+    visitor(node);
+    traverse(node->right, visitor, traversal);
+    break;
+  case POSTORDER:
+    traverse(node->left, visitor, traversal);
+    traverse(node->right, visitor, traversal);
+    visitor(node);
+    break;
+  default:
+    visitor(node);
+    break;
+  }
+}
+
+/**
+ * Frees the memory allocated for a node in a tree
+ *
+ * @param node The node in the binary tree to free
+ */
+static void destructor(Node *node) { free(node); }
+
+/**
+ * Frees the memory associated with each node in a binary tree.
+ *
+ * @param root The root of the tree
+ */
+void destroy(Node *root) { traverse(root, destructor, POSTORDER); }
+
+/**
+ * A helper method to print out a visual representation of the tree
+ *
+ * @param node A node in a binary tree.
+ * @param level The level in the tree that the node is at
+ */
+void inspect(Node *node, int level) {
+  if (!node)
+    return;
+
+  for (int i = 0; i < level; i++)
+    printf("  ");
+  printf("(%d)\n", node->data);
+  inspect(node->left, level + 1);
+  inspect(node->right, level + 1);
+}
src/02/01/binary_tree.h
@@ -0,0 +1,30 @@
+/**
+ * A struct to represent a node in a Binary Tree
+ */
+struct node {
+  int data;
+  struct node *left;
+  struct node *right;
+};
+
+typedef struct node Node;
+
+/**
+ * A signature of a function pointer
+ * that can be used to traverse a binary tree.
+ */
+typedef void(Visitor)(Node* node);
+
+/**
+ * The different types of traversals that the binary tree can perform
+ */
+enum Traversal {
+  INORDER = 1,   // In order traversal
+  PREORDER = 2,  // Pre order traversal
+  POSTORDER = 4  // Post order traversal
+};
+
+Node *initialize(int data);
+void traverse(Node *node, Visitor visitor, enum Traversal traversal);
+void destroy(Node *head);
+void inspect(Node *head, int level);
src/02/01/binary_tree_test.c
@@ -0,0 +1,397 @@
+#include "binary_tree.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+int visited[32];
+Node *nodes[32];
+int visited_count;
+
+Describe(BinaryTree);
+BeforeEach(BinaryTree) {
+  memset(visited, 0, sizeof(visited));
+  memset(nodes, 0, sizeof(nodes));
+  visited_count = 0;
+}
+AfterEach(BinaryTree) {}
+
+void visitor(Node *node) {
+  visited[visited_count] = node->data;
+  nodes[visited_count] = node;
+  visited_count++;
+}
+
+Node *next(Node *self, Node *x, enum Traversal traversal) {
+  traverse(self, visitor, traversal);
+
+  for (int i = 0; i < visited_count; i++)
+    if (nodes[i] == x)
+      return nodes[i + 1];
+  return NULL;
+}
+
+Node *preorder_next(Node *self, Node *x) { return next(self, x, PREORDER); }
+
+Node *inorder_next(Node *self, Node *x) { return next(self, x, INORDER); }
+
+Node *postorder_next(Node *self, Node *x) { return next(self, x, POSTORDER); }
+
+Ensure(BinaryTree, when_traversing_in_preorder_when_the_tree_is_empty) {
+  traverse(NULL, visitor, PREORDER);
+
+  assert_that(visited_count, is_equal_to(0));
+}
+
+Ensure(BinaryTree,
+       when_traversing_in_preorder_when_the_tree_has_a_single_node) {
+  Node *node = initialize(100);
+
+  traverse(node, visitor, PREORDER);
+
+  assert_that(visited_count, is_equal_to(1));
+  assert_that(visited[0], is_equal_to(100));
+  destroy(node);
+}
+
+Ensure(BinaryTree, when_traversing_in_preorder_when_the_tree_has_a_left_node) {
+  Node *node = initialize(100);
+  node->left = initialize(200);
+
+  traverse(node, visitor, PREORDER);
+
+  assert_that(visited_count, is_equal_to(2));
+  assert_that(visited[0], is_equal_to(100));
+  assert_that(visited[1], is_equal_to(200));
+  destroy(node);
+}
+
+Ensure(BinaryTree, when_traversing_in_preorder_when_the_tree_has_a_right_node) {
+  Node *node = initialize(100);
+  node->right = initialize(300);
+
+  traverse(node, visitor, PREORDER);
+
+  assert_that(visited_count, is_equal_to(2));
+  assert_that(visited[0], is_equal_to(100));
+  assert_that(visited[1], is_equal_to(300));
+  destroy(node);
+}
+
+Ensure(BinaryTree,
+       when_traversing_in_preorder_when_the_tree_has_a_left_and_right_node) {
+  Node *node = initialize(100);
+  node->left = initialize(200);
+  node->right = initialize(300);
+
+  traverse(node, visitor, PREORDER);
+
+  assert_that(visited_count, is_equal_to(3));
+  assert_that(visited[0], is_equal_to(100));
+  assert_that(visited[1], is_equal_to(200));
+  assert_that(visited[2], is_equal_to(300));
+  destroy(node);
+}
+
+Ensure(BinaryTree,
+       when_traversing_in_preorder_when_the_tree_has_multiple_levels) {
+  Node *node = initialize(100);
+  node->left = initialize(200);
+  node->right = initialize(300);
+
+  node->left->left = initialize(400);
+  node->left->right = initialize(500);
+
+  traverse(node, visitor, PREORDER);
+
+  assert_that(visited_count, is_equal_to(5));
+  assert_that(visited[0], is_equal_to(100));
+  assert_that(visited[1], is_equal_to(200));
+  assert_that(visited[2], is_equal_to(400));
+  assert_that(visited[3], is_equal_to(500));
+  assert_that(visited[4], is_equal_to(300));
+  destroy(node);
+}
+
+Ensure(BinaryTree, when_traversing_in_postorder_when_the_tree_is_empty) {
+  traverse(NULL, visitor, POSTORDER);
+
+  assert_that(visited_count, is_equal_to(0));
+}
+
+Ensure(BinaryTree,
+       when_traversing_in_postorder_when_the_tree_has_a_single_node) {
+  Node *node = initialize(100);
+
+  traverse(node, visitor, POSTORDER);
+
+  assert_that(visited_count, is_equal_to(1));
+  assert_that(visited[0], is_equal_to(100));
+  destroy(node);
+}
+
+Ensure(BinaryTree, when_traversing_in_postorder_when_the_tree_has_a_left_node) {
+  Node *node = initialize(100);
+  node->left = initialize(200);
+
+  traverse(node, visitor, POSTORDER);
+
+  assert_that(visited_count, is_equal_to(2));
+  assert_that(visited[0], is_equal_to(200));
+  assert_that(visited[1], is_equal_to(100));
+  destroy(node);
+}
+
+Ensure(BinaryTree,
+       when_traversing_in_postorder_when_the_tree_has_a_right_node) {
+  Node *node = initialize(100);
+  node->right = initialize(300);
+
+  traverse(node, visitor, POSTORDER);
+
+  assert_that(visited_count, is_equal_to(2));
+  assert_that(visited[0], is_equal_to(300));
+  assert_that(visited[1], is_equal_to(100));
+  destroy(node);
+}
+
+Ensure(BinaryTree,
+       when_traversing_in_postorder_when_the_tree_has_a_left_and_right_node) {
+  Node *node = initialize(100);
+  node->left = initialize(200);
+  node->right = initialize(300);
+
+  traverse(node, visitor, POSTORDER);
+
+  assert_that(visited_count, is_equal_to(3));
+  assert_that(visited[0], is_equal_to(200));
+  assert_that(visited[1], is_equal_to(300));
+  assert_that(visited[2], is_equal_to(100));
+  destroy(node);
+}
+
+Ensure(BinaryTree,
+       when_traversing_in_postorder_when_the_tree_has_multiple_levels) {
+  Node *node = initialize(100);
+  node->left = initialize(200);
+  node->right = initialize(300);
+
+  node->left->left = initialize(400);
+  node->left->right = initialize(500);
+
+  traverse(node, visitor, POSTORDER);
+
+  assert_that(visited_count, is_equal_to(5));
+  assert_that(visited[0], is_equal_to(400));
+  assert_that(visited[1], is_equal_to(500));
+  assert_that(visited[2], is_equal_to(200));
+  assert_that(visited[3], is_equal_to(300));
+  assert_that(visited[4], is_equal_to(100));
+  destroy(node);
+}
+
+Ensure(BinaryTree, when_traversing_inorder_when_the_tree_is_empty) {
+  traverse(NULL, visitor, INORDER);
+
+  assert_that(visited_count, is_equal_to(0));
+}
+
+Ensure(BinaryTree, when_traversing_inorder_when_the_tree_has_a_single_node) {
+  Node *node = initialize(100);
+
+  traverse(node, visitor, INORDER);
+
+  assert_that(visited_count, is_equal_to(1));
+  assert_that(visited[0], is_equal_to(100));
+  destroy(node);
+}
+
+Ensure(BinaryTree, when_traversing_inorder_when_the_tree_has_a_left_node) {
+  Node *node = initialize(100);
+  node->left = initialize(200);
+
+  traverse(node, visitor, INORDER);
+
+  assert_that(visited_count, is_equal_to(2));
+  assert_that(visited[0], is_equal_to(200));
+  assert_that(visited[1], is_equal_to(100));
+  destroy(node);
+}
+
+Ensure(BinaryTree, when_traversing_inorder_when_the_tree_has_a_right_node) {
+  Node *node = initialize(100);
+  node->right = initialize(300);
+
+  traverse(node, visitor, INORDER);
+
+  assert_that(visited_count, is_equal_to(2));
+  assert_that(visited[0], is_equal_to(100));
+  assert_that(visited[1], is_equal_to(300));
+  destroy(node);
+}
+
+Ensure(BinaryTree,
+       when_traversing_inorder_when_the_tree_has_a_left_and_right_node) {
+  Node *node = initialize(100);
+  node->left = initialize(200);
+  node->right = initialize(300);
+
+  traverse(node, visitor, INORDER);
+
+  assert_that(visited_count, is_equal_to(3));
+  assert_that(visited[0], is_equal_to(200));
+  assert_that(visited[1], is_equal_to(100));
+  assert_that(visited[2], is_equal_to(300));
+  destroy(node);
+}
+
+Ensure(BinaryTree, when_traversing_inorder_when_the_tree_has_multiple_levels) {
+  Node *node = initialize(100);
+  node->left = initialize(200);
+  node->right = initialize(300);
+
+  node->left->left = initialize(400);
+  node->left->right = initialize(500);
+
+  traverse(node, visitor, INORDER);
+
+  assert_that(visited_count, is_equal_to(5));
+  assert_that(visited[0], is_equal_to(400));
+  assert_that(visited[1], is_equal_to(200));
+  assert_that(visited[2], is_equal_to(500));
+  assert_that(visited[3], is_equal_to(100));
+  assert_that(visited[4], is_equal_to(300));
+  destroy(node);
+}
+
+Ensure(BinaryTree, when_finding_the_next_node_in_a_preorder_traversal) {
+  Node *a = initialize(100);
+  Node *b = initialize(200);
+  Node *c = initialize(300);
+  Node *d = initialize(400);
+  Node *e = initialize(500);
+
+  a->left = b;
+  a->right = c;
+  b->left = d;
+  b->right = e;
+
+  assert_that(preorder_next(a, a), is_equal_to(b));
+  assert_that(preorder_next(a, b), is_equal_to(d));
+  assert_that(preorder_next(a, c), is_equal_to(a));
+  assert_that(preorder_next(a, d), is_equal_to(e));
+  assert_that(preorder_next(a, e), is_equal_to(c));
+
+  destroy(a);
+}
+
+Ensure(BinaryTree, when_finding_the_next_node_in_a_inorder_traversal) {
+  Node *a = initialize(100);
+  Node *b = initialize(200);
+  Node *c = initialize(300);
+  Node *d = initialize(400);
+  Node *e = initialize(500);
+
+  a->left = b;
+  a->right = c;
+  b->left = d;
+  b->right = e;
+
+  assert_that(inorder_next(a, a), is_equal_to(c));
+  assert_that(inorder_next(a, b), is_equal_to(e));
+  assert_that(inorder_next(a, c), is_equal_to(d));
+  assert_that(inorder_next(a, d), is_equal_to(b));
+  assert_that(inorder_next(a, e), is_equal_to(a));
+
+  destroy(a);
+}
+
+Ensure(BinaryTree, when_finding_the_next_node_in_a_postorder_traversal) {
+  Node *a = initialize(100);
+  Node *b = initialize(200);
+  Node *c = initialize(300);
+  Node *d = initialize(400);
+  Node *e = initialize(500);
+
+  a->left = b;
+  a->right = c;
+  b->left = d;
+  b->right = e;
+
+  assert_that(postorder_next(a, a), is_equal_to(NULL));
+  assert_that(postorder_next(a, b), is_equal_to(c));
+  assert_that(postorder_next(a, c), is_equal_to(a));
+  assert_that(postorder_next(a, d), is_equal_to(e));
+  assert_that(postorder_next(a, e), is_equal_to(b));
+
+  destroy(a);
+}
+
+TestSuite *binary_tree_tests() {
+  TestSuite *suite = create_test_suite();
+
+  add_test_with_context(suite, BinaryTree,
+                        when_traversing_in_preorder_when_the_tree_is_empty);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_in_preorder_when_the_tree_has_a_single_node);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_in_preorder_when_the_tree_has_a_left_node);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_in_preorder_when_the_tree_has_a_right_node);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_in_preorder_when_the_tree_has_a_left_and_right_node);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_in_preorder_when_the_tree_has_multiple_levels);
+
+  add_test_with_context(suite, BinaryTree,
+                        when_traversing_in_postorder_when_the_tree_is_empty);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_in_postorder_when_the_tree_has_a_single_node);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_in_postorder_when_the_tree_has_a_left_node);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_in_postorder_when_the_tree_has_a_right_node);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_in_postorder_when_the_tree_has_a_left_and_right_node);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_in_postorder_when_the_tree_has_multiple_levels);
+
+  add_test_with_context(suite, BinaryTree,
+                        when_traversing_inorder_when_the_tree_is_empty);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_inorder_when_the_tree_has_a_single_node);
+  add_test_with_context(suite, BinaryTree,
+                        when_traversing_inorder_when_the_tree_has_a_left_node);
+  add_test_with_context(suite, BinaryTree,
+                        when_traversing_inorder_when_the_tree_has_a_right_node);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_inorder_when_the_tree_has_a_left_and_right_node);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_traversing_inorder_when_the_tree_has_multiple_levels);
+
+  add_test_with_context(suite, BinaryTree,
+                        when_finding_the_next_node_in_a_preorder_traversal);
+  add_test_with_context(suite, BinaryTree,
+                        when_finding_the_next_node_in_a_inorder_traversal);
+  add_test_with_context(suite, BinaryTree,
+                        when_finding_the_next_node_in_a_postorder_traversal);
+
+  return suite;
+}
+
+int main(int argc, char **argv) {
+  TestSuite *suite = create_test_suite();
+  add_suite(suite, binary_tree_tests());
+  return run_test_suite(suite, create_text_reporter());
+}
src/02/01/main.c
@@ -0,0 +1,50 @@
+#include "binary_tree.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static Node *nodes[32];
+static int visited_count;
+
+static void visitor(Node *node) {
+  nodes[visited_count] = node;
+  visited_count++;
+}
+
+void print_traversal(Node *tree, enum Traversal direction) {
+  visited_count = 0;
+  memset(nodes, 0, sizeof(nodes));
+
+  traverse(tree, visitor, direction);
+
+  for (int i = 0; i < visited_count; i++)
+    printf("%d ", nodes[i]->data);
+  printf("\n");
+}
+
+int main(int argc, char *argv[]) {
+  printf("=== COMP-272 - Assignment 02 - Question 01 ===\n");
+
+  Node *a = initialize(100);
+  Node *b = initialize(200);
+  Node *c = initialize(300);
+  Node *d = initialize(400);
+  Node *e = initialize(500);
+
+  a->left = b;
+  a->right = c;
+  b->left = d;
+  b->right = e;
+  inspect(a, 0);
+
+  printf("\n=== Pre order traversal ===\n");
+  print_traversal(a, PREORDER);
+
+  printf("\n=== In order traversal ===\n");
+  print_traversal(a, INORDER);
+
+  printf("\n=== Post order traversal ===\n");
+  print_traversal(a, POSTORDER);
+
+  return 0;
+}
src/02/01/Makefile
@@ -0,0 +1,37 @@
+#!/usr/bin/make -f
+SHELL=/bin/sh
+
+CC=clang
+TEST_LIBS = -lcgreen
+
+BUILDDIR := build
+OBJS := $(addprefix $(BUILDDIR)/,binary_tree.o)
+TEST_OBJS := $(addprefix $(BUILDDIR)/,binary_tree_test.o)
+
+$(BUILDDIR)/%.o : %.c
+	$(COMPILE.c) $(OUTPUT_OPTION) $<
+
+.PHONY: all
+all: $(OBJS) $(BUILDDIR)/main.o
+	$(CC) $(OBJS) $(BUILDDIR)/main.o -o $(BUILDDIR)/program
+
+.PHONY: test
+test: $(OBJS) $(TEST_OBJS)
+	$(CC) $(OBJS) $(TEST_OBJS) $(TEST_LIBS) -o $(BUILDDIR)/test
+
+$(OBJS): | $(BUILDDIR)
+
+$(TEST_OBJS): | $(BUILDDIR)
+
+$(BUILDDIR):
+	mkdir $(BUILDDIR)
+
+.PHONY: clean
+clean:
+	rm -fr build
+
+run : all
+	./build/program
+
+run_test : test
+	cgreen-runner -c -v $(BUILDDIR)/test
src/02/01/README.md
@@ -0,0 +1,4 @@
+Design an algorithm for the following operations for a binary tree BT, and show the worst-case running times for each implementation:
+* preorderNext(x): return the node visited after node x in a pre-order traversal of BT.
+* postorderNext(x): return the node visited after node x in a post-order traversal of BT.
+* inorderNext(x): return the node visited after node x in an in-order traversal of BT.
src/02/02/btree.c
@@ -0,0 +1,75 @@
+#include "btree.h"
+#include <limits.h>
+#include <stdio.h>
+
+/**
+ * A helper function used
+ * to print a visual representation
+ * of a Binary Tree
+ */
+static void inspect(BTree *tree, int level) {
+  if (!tree)
+    return;
+
+  for (int i = 0; i < level; i++)
+    printf("  ");
+
+  printf("%2d\n", tree->data);
+  inspect(tree->left, level + 1);
+  inspect(tree->right, level + 1);
+}
+
+/**
+ * A recursive function that can
+ * be used to ensure that each node in
+ * a Binary Tree satisfies the
+ * Binary Search Tree property.
+ *
+ * @param tree A tree or subtree to verify
+ * @param min the minimum value that each node must be greater than
+ * @param max the maximum value that each node must be less than.
+ * @return Returns tree when the tree is a binary search tree, otherwise false.
+ *
+ *
+ */
+static bool in_range(BTree *tree, int min, int max) {
+  if (!tree)
+    return true;
+
+  int data = tree->data;
+  if (data < min || data > max)
+    return false;
+
+  return in_range(tree->left, min, data) && in_range(tree->right, data, max);
+}
+
+/**
+ * Initializes a binary tree.
+ *
+ * @param the data to assign to the root node in the tree.
+ * @return the root of the tree.
+ */
+BTree *btree_init(int data) {
+  BTree *tree = malloc(sizeof(BTree));
+  tree->left = NULL;
+  tree->right = NULL;
+  tree->data = data;
+  return tree;
+}
+
+/**
+ * A function that determines if a binary tree
+ * is a binary search tree or not.
+ *
+ * @param tree The root of the tree to inspect
+ * @return Returns true when the tree is a binary search tree;
+ */
+bool btree_is_bst(BTree *tree) { return in_range(tree, INT_MIN, INT_MAX); }
+
+/**
+ * A helper function used to print a visual
+ * representation of the binary tree.
+ *
+ * @param tree The tree or subtree to inspect
+ */
+void btree_inspect(BTree *tree) { inspect(tree, 0); }
src/02/02/btree.h
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <stdbool.h>
+
+typedef struct btree_node {
+  struct btree_node *left;
+  struct btree_node *right;
+  int data;
+} BTree;
+
+BTree *btree_init(int data);
+bool btree_is_bst(BTree *tree);
+void btree_inspect(BTree *tree);
src/02/02/btree_test.c
@@ -0,0 +1,88 @@
+#include "btree.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Describe(BinaryTree);
+BeforeEach(BinaryTree) {}
+AfterEach(BinaryTree) {}
+
+Ensure(BinaryTree, when_a_tree_is_NULL) {
+  assert_that(btree_is_bst(NULL), is_equal_to(true));
+}
+
+Ensure(BinaryTree, when_a_tree_has_a_single_node) {
+  BTree *tree = btree_init(100);
+
+  assert_that(btree_is_bst(tree), is_equal_to(true));
+}
+
+Ensure(BinaryTree, when_the_node_on_the_left_is_greater_than_the_root) {
+  BTree *tree = btree_init(100);
+  tree->left = btree_init(200);
+
+  assert_that(btree_is_bst(tree), is_equal_to(false));
+}
+
+Ensure(BinaryTree, when_the_node_on_the_right_is_less_than_the_root) {
+  BTree *tree = btree_init(200);
+  tree->right = btree_init(100);
+
+  assert_that(btree_is_bst(tree), is_equal_to(false));
+}
+
+Ensure(BinaryTree, when_a_node_on_the_left_subtree_is_less_than_an_ancestor) {
+  BTree *tree = btree_init(300);
+  tree->left = btree_init(100);
+  tree->left->right = btree_init(400);
+
+  assert_that(btree_is_bst(tree), is_equal_to(false));
+}
+
+Ensure(BinaryTree,
+       when_a_node_on_the_right_subtree_is_greater_than_an_ancestor) {
+  BTree *tree = btree_init(300);
+  tree->right = btree_init(500);
+  tree->right->left = btree_init(200);
+
+  assert_that(btree_is_bst(tree), is_equal_to(false));
+}
+
+Ensure(BinaryTree, when_the_tree_is_a_binary_search_tree) {
+  BTree *tree = btree_init(10);
+  tree->left = btree_init(-5);
+  tree->left->left = btree_init(-10);
+  tree->left->right = btree_init(5);
+
+  tree->right = btree_init(25);
+  tree->right->left = btree_init(23);
+  tree->right->right = btree_init(36);
+
+  assert_that(btree_is_bst(tree), is_equal_to(true));
+}
+
+TestSuite *binary_search_tree_tests() {
+  TestSuite *suite = create_test_suite();
+
+  add_test_with_context(suite, BinaryTree, when_a_tree_is_NULL);
+  add_test_with_context(suite, BinaryTree, when_a_tree_has_a_single_node);
+  add_test_with_context(suite, BinaryTree,
+                        when_the_node_on_the_left_is_greater_than_the_root);
+  add_test_with_context(suite, BinaryTree,
+                        when_the_node_on_the_right_is_less_than_the_root);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_a_node_on_the_left_subtree_is_less_than_an_ancestor);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_a_node_on_the_right_subtree_is_greater_than_an_ancestor);
+  add_test_with_context(suite, BinaryTree,
+                        when_the_tree_is_a_binary_search_tree);
+
+  return suite;
+}
+
+int main(int argc, char **argv) {
+  TestSuite *suite = create_test_suite();
+  add_suite(suite, binary_search_tree_tests());
+  return run_test_suite(suite, create_text_reporter());
+}
src/02/02/main.c
@@ -0,0 +1,48 @@
+#include "btree.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+void investigate(BTree *tree) {
+  btree_inspect(tree);
+  printf("Is a binary search tree? %c\n\n", btree_is_bst(tree) ? 'y' : 'n');
+}
+
+BTree *build_binary_search_tree() {
+  BTree *tree = btree_init(10);
+  tree->left = btree_init(-5);
+  tree->left->left = btree_init(-10);
+  tree->left->right = btree_init(5);
+
+  tree->right = btree_init(25);
+  tree->right->left = btree_init(23);
+  tree->right->right = btree_init(36);
+  return tree;
+}
+
+BTree *build_binary_tree() {
+  BTree *tree = btree_init(10);
+  tree->left = btree_init(0);
+  tree->left->left = btree_init(-1);
+  tree->left->right = btree_init(21);
+
+  tree->right = btree_init(25);
+  tree->right->left = btree_init(16);
+  tree->right->right = btree_init(32);
+
+  return tree;
+}
+
+int main(int argc, char *argv[]) {
+  printf("=== COMP-272 - Assignment 02 - Question 02 ===\n");
+
+  printf("Binary Search Tree\n");
+  printf("---------\n");
+  investigate(build_binary_search_tree());
+
+  printf("Binary Tree\n");
+  printf("---------\n");
+  investigate(build_binary_tree());
+
+  printf("Bye\n");
+  return 0;
+}
src/02/02/Makefile
@@ -0,0 +1,37 @@
+#!/usr/bin/make -f
+SHELL=/bin/sh
+
+CC=clang
+TEST_LIBS = -lcgreen
+
+BUILDDIR := build
+OBJS := $(addprefix $(BUILDDIR)/,btree.o)
+TEST_OBJS := $(addprefix $(BUILDDIR)/,btree_test.o)
+
+$(BUILDDIR)/%.o : %.c
+	$(COMPILE.c) $(OUTPUT_OPTION) $<
+
+.PHONY: all
+all: $(OBJS) $(BUILDDIR)/main.o
+	$(CC) $(OBJS) $(BUILDDIR)/main.o -o $(BUILDDIR)/program
+
+.PHONY: test
+test: $(OBJS) $(TEST_OBJS)
+	$(CC) $(OBJS) $(TEST_OBJS) $(TEST_LIBS) -o $(BUILDDIR)/test
+
+$(OBJS): | $(BUILDDIR)
+
+$(TEST_OBJS): | $(BUILDDIR)
+
+$(BUILDDIR):
+	mkdir $(BUILDDIR)
+
+.PHONY: clean
+clean:
+	rm -fr build
+
+run : all
+	./build/program
+
+run_test : test
+	cgreen-runner -c -v $(BUILDDIR)/test
src/02/02/README.md
@@ -0,0 +1,3 @@
+Design a recursive linear-time algorithm that
+tests whether a binary tree satisfies the
+search tree order property at every node.
src/02/03/btree.c
@@ -0,0 +1,176 @@
+#include "btree.h"
+#include "list.h"
+#include "stack.h"
+#include <stdio.h>
+
+/**
+ * A helper function used to print a visual
+ * representation of a binary tree.
+ *
+ * @param tree the tree or subtree to inspect
+ * @param level the level of the subtree
+ */
+static void inspect(BTree *tree, int level) {
+  if (!tree)
+    return;
+
+  for (int i = 0; i < level; i++)
+    printf("  ");
+
+  printf("%2d\n", tree->data);
+  inspect(tree->left, level + 1);
+  inspect(tree->right, level + 1);
+}
+
+/**
+ * Initializes an new subtree in a binary tree
+ *
+ * @param parent the parent of the new btree node
+ * @param data the data to assign to the root of the tree.
+ * @return Returns the new subtree
+ */
+BTree *btree_initialize(BTree *parent, int data) {
+  BTree *tree = malloc(sizeof(BTree));
+  tree->parent = parent;
+  tree->left = NULL;
+  tree->right = NULL;
+  tree->data = data;
+  return tree;
+}
+
+/**
+ * Converts a binary tree into a linked list
+ * using an in order traversal.
+ *
+ * @param tree The binary tree to convert
+ * @return Returns the head of a linked list.
+ */
+List *btree_to_list(BTree *tree) {
+  if (tree == NULL)
+    return NULL;
+
+  List *list = NULL;
+  Stack *stack = stack_init();
+  BTree *tmp = tree;
+
+  while (true) {
+    if (tmp) {
+      stack_push(stack, tmp);
+      tmp = tmp->left;
+    } else if (stack_size(stack) == 0) {
+      break;
+    } else {
+      tmp = stack_pop(stack);
+      if (list)
+        list_add(list, tmp);
+      else
+        list = list_initialize(tree);
+      tmp = tmp->right;
+    }
+  }
+
+  return list;
+}
+
+/**
+ * Calculates the size of a binary tree
+ *
+ * @param tree the tree to inspect
+ * @return Returns the # of nodes in the binary tree.
+ */
+int btree_size(BTree *tree) {
+  List *list = btree_to_list(tree);
+  return list ? list_size(list) : 0;
+}
+
+/**
+ * Determines if a subtree in a binary tree
+ * can be used as a scapegoat to rebalance
+ * the tree.
+ *
+ * @param tree the subtree to investigate
+ * @return Returns true then subtree can be used as a scapegoat.
+ */
+bool btree_is_scapegoat(BTree *tree) {
+  int size = btree_size(tree);
+  int parent_size = btree_size(tree->parent);
+
+  return ((size * 3) > (parent_size * 2));
+}
+
+/**
+ * Rebuilds a subtree by converting it
+ * to a list then rebuilding a binary tree.
+ *
+ * @param tree The tree to rebuild
+ * @return Returns the new binary tree.
+ */
+BTree *btree_rebuild(BTree *tree) {
+  List *list = btree_to_list(tree->parent);
+  int mid = (list_size(list) / 2) - 1;
+  List *new_root = list_get(list, mid);
+  int data = ((BTree *)new_root->data)->data;
+  BTree *new_broot = btree_initialize(NULL, data);
+
+  for (int i = 0; i < list_size(list); i++) {
+    if (i == mid)
+      continue;
+
+    int data = ((BTree *)list_get(list, i)->data)->data;
+    btree_insert(new_broot, data);
+  }
+  return new_broot;
+}
+
+/**
+ * Rebalances a binary tree starting from
+ * the bottom up.
+ *
+ * @param tree the subtree to rebalance
+ * @return Returns the new root of the binary tree.
+ */
+BTree *btree_rebalance(BTree *tree) {
+  if (!tree->parent)
+    return tree;
+
+  if (btree_is_scapegoat(tree))
+    return btree_rebuild(tree);
+
+  return btree_rebalance(tree->parent);
+}
+
+/**
+ * Inserts a new node into a binary tree.
+ *
+ * @param tree the tree to insert the new new into
+ * @return Returns the root of the tree.
+ */
+BTree *btree_insert(BTree *tree, int data) {
+  if (!tree)
+    return btree_initialize(NULL, data);
+
+  if (data <= tree->data)
+    if (tree->left)
+      return btree_insert(tree->left, data);
+    else {
+      tree->left = btree_initialize(tree, data);
+      return btree_rebalance(tree->left);
+    }
+  else if (tree->right)
+    return btree_insert(tree->right, data);
+  else {
+    tree->right = btree_initialize(tree, data);
+    return btree_rebalance(tree->right);
+  }
+
+  return tree;
+}
+
+/**
+ * A helper function used to print
+ * a visual representation of a binary
+ * tree.
+ *
+ * @param tree The root of the tree to inspect
+ */
+void btree_inspect(BTree *tree) { inspect(tree, 0); }
src/02/03/btree.h
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <stdbool.h>
+
+typedef struct btree_node {
+  struct btree_node *left;
+  struct btree_node *right;
+  struct btree_node *parent;
+  int data;
+} BTree;
+
+BTree *btree_initialize(BTree *parent, int data);
+BTree *btree_insert(BTree *root, int data);
+BTree *btree_rebalance(BTree *tree);
+void btree_inspect(BTree *tree);
+int btree_size(BTree *tree);
src/02/03/btree_test.c
@@ -0,0 +1,153 @@
+#include "btree.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Describe(BinaryTree);
+BeforeEach(BinaryTree) {}
+AfterEach(BinaryTree) {}
+
+Ensure(BinaryTree, when_the_tree_is_NULL) {
+  BTree *tree = btree_insert(NULL, 10);
+
+  assert_that(tree, is_not_equal_to(NULL));
+  assert_that(tree->data, is_equal_to(10));
+}
+
+Ensure(
+    BinaryTree,
+    when_inserting_an_item_less_than_the_root_in_a_tree_it_creates_a_node_on_the_left_side) {
+  BTree *tree = btree_insert(NULL, 10);
+  btree_insert(tree, -5);
+
+  assert_that(tree->left, is_not_equal_to(NULL));
+  assert_that(tree->left->data, is_equal_to(-5));
+}
+
+Ensure(
+    BinaryTree,
+    when_inserting_an_item_greater_than_the_root_in_a_tree_it_creates_a_node_on_the_right_side) {
+  BTree *tree = btree_insert(NULL, 10);
+
+  btree_insert(tree, 16);
+
+  assert_that(tree->right, is_not_equal_to(NULL));
+  assert_that(tree->right->data, is_equal_to(16));
+}
+
+Ensure(
+    BinaryTree,
+    when_inserting_an_item_equal_to_the_root_in_a_tree_it_creates_a_node_on_the_left_side) {
+  BTree *tree = btree_insert(NULL, 10);
+
+  btree_insert(tree, 10);
+
+  assert_that(tree->left, is_not_equal_to(NULL));
+  assert_that(tree->left->data, is_equal_to(10));
+}
+
+Ensure(
+    BinaryTree,
+    when_inserting_multiple_items_into_a_tree_it_inserts_in_the_correct_position) {
+  BTree *tree = btree_insert(NULL, 10);
+
+  btree_insert(tree, -5);
+  btree_insert(tree, 16);
+
+  assert_that(tree->data, is_equal_to(10));
+  assert_that(tree->left->data, is_equal_to(-5));
+  assert_that(tree->right->data, is_equal_to(16));
+
+  btree_insert(tree, -8);
+
+  assert_that(tree->left->left, is_not_equal_to(NULL));
+  assert_that(tree->left->left->data, is_equal_to(-8));
+
+  btree_insert(tree, 7);
+
+  assert_that(tree->left->right, is_not_equal_to(NULL));
+  assert_that(tree->left->right->data, is_equal_to(7));
+
+  btree_insert(tree, 18);
+
+  assert_that(tree->right->right, is_not_equal_to(NULL));
+  assert_that(tree->right->right->data, is_equal_to(18));
+
+  btree_insert(tree, 6);
+
+  assert_that(tree->left->right->left, is_not_equal_to(NULL));
+  assert_that(tree->left->right->left->data, is_equal_to(6));
+}
+
+Ensure(BinaryTree, when_rebalancing_a_tree) {
+  BTree *tree = btree_insert(NULL, 1);
+  tree->right = btree_initialize(tree, 5);
+  tree->right->left = btree_initialize(tree->right, 2);
+  tree->right->left->right = btree_initialize(tree->right->left, 4);
+
+  tree = btree_rebalance(tree->right->left->right);
+
+  assert_that(tree, is_not_equal_to(NULL));
+  assert_that(tree->data, is_equal_to(2));
+
+  assert_that(tree->left->data, is_equal_to(1));
+  assert_that(tree->right->data, is_equal_to(4));
+  assert_that(tree->right->right->data, is_equal_to(5));
+}
+
+Ensure(
+    BinaryTree,
+    when_inserting_items_described_in_the_assignment_it_inserts_in_the_expected_position_in_the_tree) {
+  BTree *tree = btree_insert(NULL, 1);
+  tree = btree_insert(tree, 5);
+  tree = btree_insert(tree, 2);
+  tree = btree_insert(tree, 4);
+  tree = btree_insert(tree, 3);
+
+  assert_that(tree, is_not_equal_to(NULL));
+  assert_that(tree->data, is_equal_to(2));
+  assert_that(tree->left->data, is_equal_to(1));
+  assert_that(tree->right->data, is_equal_to(4));
+  assert_that(tree->right->right->data, is_equal_to(5));
+}
+
+Ensure(BinaryTree, when_calculating_the_size_of_the_tree) {
+  BTree *tree = btree_insert(NULL, 1);
+  tree = btree_insert(tree, 5);
+  tree = btree_insert(tree, 2);
+  tree = btree_insert(tree, 4);
+  tree = btree_insert(tree, 3);
+
+  assert_that(btree_size(tree), is_equal_to(5));
+}
+
+TestSuite *binary_search_tree_tests() {
+  TestSuite *suite = create_test_suite();
+
+  add_test_with_context(suite, BinaryTree, when_the_tree_is_NULL);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_inserting_an_item_less_than_the_root_in_a_tree_it_creates_a_node_on_the_left_side);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_inserting_an_item_greater_than_the_root_in_a_tree_it_creates_a_node_on_the_right_side);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_inserting_an_item_equal_to_the_root_in_a_tree_it_creates_a_node_on_the_left_side);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_inserting_multiple_items_into_a_tree_it_inserts_in_the_correct_position);
+  add_test_with_context(suite, BinaryTree, when_rebalancing_a_tree);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_inserting_items_described_in_the_assignment_it_inserts_in_the_expected_position_in_the_tree);
+
+  add_test_with_context(suite, BinaryTree,
+                        when_calculating_the_size_of_the_tree);
+  return suite;
+}
+
+int main(int argc, char **argv) {
+  TestSuite *suite = create_test_suite();
+  add_suite(suite, binary_search_tree_tests());
+  return run_test_suite(suite, create_text_reporter());
+}
src/02/03/list.c
@@ -0,0 +1,86 @@
+#include "list.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Initializes a new node for a linked list.
+ *
+ * @param data The data to bind to the new node in the list.
+ * @return Returns a new linked list node
+ */
+List *list_initialize(void *data) {
+  List *node = malloc(sizeof(List));
+  node->data = data;
+  node->next = NULL;
+  return node;
+}
+
+/**
+ * Adds a new item to the tail of a linked list
+ *
+ * @param head The head of a linked list
+ * @param data The data to add to the tail of a linked list
+ * @return Returns the new tail node
+ */
+List *list_add(List *head, void *data) {
+  List *tail;
+  List *tmp = head;
+
+  while (tmp) {
+    if (!tmp->next)
+      break;
+    tmp = tmp->next;
+  }
+  tail = tmp;
+  tail->next = list_initialize(data);
+  return tail->next;
+}
+
+/**
+ * Returns a specific node by zero based index in a linked list.
+ *
+ * @param self the head of the linked list
+ * @param index the offset from the head of the node to return
+ * @return Returns the node at the specified offset or NULL.
+ */
+List *list_get(List *self, int index) {
+  if (!self || index < 0)
+    return NULL;
+
+  while (index > 0 && self) {
+    self = self->next;
+    index--;
+  }
+  return self;
+}
+
+/**
+ * Returns the total number of nodes in a linked list.
+ *
+ * @param head The head of a linked list
+ * @returns Returns the # of items in the list.
+ */
+int list_size(List *head) {
+  int i = 0;
+  for (List *tmp = head; tmp && tmp != NULL; tmp = tmp->next)
+    i++;
+  return i;
+}
+
+/**
+ * Prints a visual representation of a linked list.
+ *
+ * @param self The head of the linked list
+ * @param printer A callback function to invoke to print each item.
+ */
+void list_inspect(List *self, Printer printer) {
+  if (!self)
+    return;
+
+  printf("[");
+  while (self) {
+    printer(self->data);
+    self = self->next;
+  }
+  printf("]\n");
+}
src/02/03/list.h
@@ -0,0 +1,10 @@
+#include "node.h"
+
+typedef void (*Printer)(void *);
+typedef struct node List;
+
+List *list_initialize(void *data);
+List *list_get(List *from, int index);
+List *list_add(List *head, void *data);
+int list_size(List *list);
+void list_inspect(List *self, Printer printer);
src/02/03/list_test.c
@@ -0,0 +1,91 @@
+#include "list.h"
+#include <cgreen/cgreen.h>
+
+Describe(List);
+BeforeEach(List) {}
+AfterEach(List) {}
+
+Ensure(List, when_getting_head) {
+  List *head = list_initialize((void *)100);
+  assert_that(list_get(head, 0), is_equal_to(head));
+  assert_that(list_get(head, 0)->data, is_equal_to(100));
+  free(head);
+}
+
+Ensure(List, when_getting_mid) {
+  List *head = list_initialize((void *)100);
+
+  List *mid = list_add(head, (void *)200);
+  list_add(head, (void *)300);
+
+  assert_that(list_get(head, 1), is_equal_to(mid));
+  assert_that(list_get(head, 1)->data, is_equal_to(200));
+
+  free(head);
+}
+
+Ensure(List, when_getting_tail) {
+  List *head = list_initialize((void *)100);
+  List *mid = list_add(head, (void *)200);
+  List *tail = list_add(head, (void *)300);
+
+  assert_that(list_get(head, 0), is_equal_to(head));
+  assert_that(list_get(head, 0)->data, is_equal_to(100));
+
+  assert_that(list_get(head, 1), is_equal_to(mid));
+  assert_that(list_get(head, 1)->data, is_equal_to(200));
+
+  assert_that(list_get(head, 2), is_equal_to(tail));
+  assert_that(list_get(head, 2)->data, is_equal_to(300));
+
+  free(head);
+}
+
+Ensure(List, when_getting_from_empty_list) {
+  assert_that(list_get(NULL, 2), is_equal_to(NULL));
+}
+
+Ensure(List, when_getting_negative_index) {
+  List *head = list_initialize((void *)100);
+
+  assert_that(list_get(head, -1), is_equal_to(NULL));
+
+  free(head);
+}
+
+Ensure(List, when_getting_index_out_of_range) {
+  List *head = list_initialize((void *)100);
+
+  assert_that(list_get(head, 1), is_equal_to(NULL));
+
+  free(head);
+}
+
+struct Person {
+  int age;
+};
+
+Ensure(List, when_adding_a_custom_datatype) {
+  struct Person *item = malloc(sizeof(struct Person));
+  item->age = 36;
+  List *head = list_initialize((void *)item);
+
+  List *result = list_get(head, 0);
+  assert_that(result, is_equal_to(head));
+
+  struct Person *p = (struct Person *)result->data;
+  assert_that(p->age, is_equal_to(36));
+}
+
+TestSuite *list_tests() {
+  TestSuite *suite = create_test_suite();
+
+  add_test_with_context(suite, List, when_getting_head);
+  add_test_with_context(suite, List, when_getting_mid);
+  add_test_with_context(suite, List, when_getting_tail);
+  add_test_with_context(suite, List, when_getting_from_empty_list);
+  add_test_with_context(suite, List, when_getting_negative_index);
+  add_test_with_context(suite, List, when_getting_index_out_of_range);
+  add_test_with_context(suite, List, when_adding_a_custom_datatype);
+  return suite;
+}
src/02/03/main.c
@@ -0,0 +1,24 @@
+#include "btree.h"
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+  printf("=== COMP-272 - Assignment 02 - Question 03 ===\n");
+  printf("Tree 1: unbalanced tree\n");
+  BTree *tree = btree_insert(NULL, 1);
+  btree_insert(tree, 5);
+  btree_insert(tree, 2);
+  btree_insert(tree, 4);
+  btree_insert(tree, 3);
+  btree_inspect(tree);
+
+  printf("Tree 2: balanced tree\n");
+  tree = btree_insert(NULL, 3);
+  btree_insert(tree, 2);
+  btree_insert(tree, 4);
+  btree_insert(tree, 1);
+  btree_insert(tree, 5);
+  btree_inspect(tree);
+
+  printf("Bye\n");
+  return 0;
+}
src/02/03/Makefile
@@ -0,0 +1,37 @@
+#!/usr/bin/make -f
+SHELL=/bin/sh
+
+CC=clang
+TEST_LIBS = -lcgreen
+
+BUILDDIR := build
+OBJS := $(addprefix $(BUILDDIR)/,btree.o list.o stack.o)
+TEST_OBJS := $(addprefix $(BUILDDIR)/,btree_test.o list_test.o stack_test.o)
+
+$(BUILDDIR)/%.o : %.c
+	$(COMPILE.c) $(OUTPUT_OPTION) $<
+
+.PHONY: all
+all: $(OBJS) $(BUILDDIR)/main.o
+	$(CC) $(OBJS) $(BUILDDIR)/main.o -o $(BUILDDIR)/program
+
+.PHONY: test
+test: $(OBJS) $(TEST_OBJS)
+	$(CC) $(OBJS) $(TEST_OBJS) $(TEST_LIBS) -o $(BUILDDIR)/test
+
+$(OBJS): | $(BUILDDIR)
+
+$(TEST_OBJS): | $(BUILDDIR)
+
+$(BUILDDIR):
+	mkdir $(BUILDDIR)
+
+.PHONY: clean
+clean:
+	rm -fr build
+
+run : all
+	./build/program
+
+run_test : test
+	cgreen-runner -c -v $(BUILDDIR)/test
src/02/03/node.h
@@ -0,0 +1,9 @@
+#ifndef NODE_H
+#define NODE_H
+
+typedef struct node {
+  struct node *next;
+  void *data;
+} Node;
+
+#endif
src/02/03/README.md
@@ -0,0 +1,3 @@
+Illustrate what happens when the sequence 1, 5, 2, 4, 3 is added to an empty
+ScapegoatTree, and show where the credits described in the proof of Lemma 8.3 go,
+and how they are used during this sequence of additions.
src/02/03/stack.c
@@ -0,0 +1,52 @@
+#include "stack.h"
+#include <stdlib.h>
+
+Node *node_init(void *data) {
+  Node *node = malloc(sizeof(Node));
+  node->next = NULL;
+  node->data = data;
+  return node;
+}
+
+Stack *stack_init() {
+  Stack *stack = malloc(sizeof(Stack));
+  stack->head = NULL;
+  return stack;
+}
+
+int stack_size(Stack *self) {
+  if (!self || !self->head)
+    return 0;
+
+  int count = 0;
+  Node *current = self->head;
+  while (current) {
+    ++count;
+    current = current->next;
+  }
+
+  return count;
+}
+
+void *stack_peek(Stack *self) {
+  if (self->head)
+    return self->head->data;
+  return NULL;
+}
+
+void stack_push(Stack *stack, void *data) {
+  Node *node = node_init(data);
+  node->next = stack->head;
+  stack->head = node;
+}
+
+void *stack_pop(Stack *self) {
+  if (self->head) {
+    Node *tmp = self->head;
+    void *data = tmp->data;
+    self->head = self->head->next;
+    free(tmp);
+    return data;
+  }
+  return NULL;
+}
src/02/03/stack.h
@@ -0,0 +1,11 @@
+#include "node.h"
+
+typedef struct {
+  Node *head;
+} Stack;
+
+Stack *stack_init();
+void *stack_peek(Stack *self);
+int stack_size(Stack *self);
+void stack_push(Stack *self, void *data);
+void *stack_pop(Stack *self);
src/02/03/stack_test.c
@@ -0,0 +1,65 @@
+#include "stack.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Describe(Stack);
+BeforeEach(Stack) {}
+AfterEach(Stack) {}
+
+Ensure(Stack, when_pushing_an_item_on_to_a_stack) {
+  Stack *stack = stack_init();
+
+  stack_push(stack, (void *)10);
+
+  assert_that(stack_size(stack), is_equal_to(1));
+  assert_that(stack_peek(stack), is_equal_to(10));
+}
+
+Ensure(Stack, when_pushing_multiple_items_on_to_a_stack) {
+  Stack *stack = stack_init();
+
+  stack_push(stack, (void *)20);
+  stack_push(stack, (void *)10);
+  stack_push(stack, (void *)50);
+
+  assert_that(stack_size(stack), is_equal_to(3));
+  assert_that(stack_peek(stack), is_equal_to(50));
+}
+
+Ensure(Stack, when_pushing_a_custom_type_on_to_a_stack) {
+  typedef struct {
+  } Item;
+
+  Stack *stack = stack_init();
+  Item *item = malloc(sizeof(Item));
+
+  stack_push(stack, item);
+
+  assert_that(stack_size(stack), is_equal_to(1));
+  assert_that(stack_peek(stack), is_equal_to(item));
+  assert_that(stack_pop(stack), is_equal_to(item));
+}
+
+Ensure(Stack, when_popping_an_item_off_of_a_stack) {
+  Stack *stack = stack_init();
+
+  stack_push(stack, (void *)20);
+  stack_push(stack, (void *)10);
+  stack_push(stack, (void *)50);
+
+  void *result = stack_pop(stack);
+
+  assert_that(stack_size(stack), is_equal_to(2));
+  assert_that(stack_peek(stack), is_equal_to(10));
+  assert_that(result, is_equal_to(50));
+}
+
+TestSuite *stack_tests() {
+  TestSuite *suite = create_test_suite();
+  add_test_with_context(suite, Stack, when_pushing_an_item_on_to_a_stack);
+  add_test_with_context(suite, Stack,
+                        when_pushing_multiple_items_on_to_a_stack);
+  add_test_with_context(suite, Stack, when_pushing_a_custom_type_on_to_a_stack);
+  add_test_with_context(suite, Stack, when_popping_an_item_off_of_a_stack);
+  return suite;
+}
src/02/04/hash.c
@@ -0,0 +1,110 @@
+#include "hash.h"
+#include "tuple.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Initialize a new hash table.
+ *
+ * @param size The number of buckets to allocate for the chash table.
+ * @return Returns the hash table.
+ */
+Hash *hash_init(int size) {
+  Hash *hash = malloc(sizeof(Hash));
+  hash->size = size;
+  hash->buckets = calloc(size, sizeof(Node));
+  return hash;
+}
+
+/**
+ * Computes a hash code for the given key.
+ *
+ * @param hash The hash table that the key is used in.
+ * @param key The key to produce a hash code for
+ * @return Returns a hash code for the given key.
+ */
+unsigned int hash_code(Hash *hash, int key) { return key % hash->size; }
+
+/**
+ * A function to search for a specific key in a linked list.
+ * This performs a O(n) search to find the matching key.
+ * A possible optimization would be to convert this to do a binary
+ * search for the given key using a binary search tree instead of a linked
+ * list.
+ *
+ * @param list The linked list to search for the given key
+ * @param key The key to search for in the linked list
+ * @return Returns the data associated with the given key.
+ */
+void *search(Node *list, int key) {
+  Node *current = list;
+
+  while (current) {
+    Tuple *t = current->data;
+    if (t->key == key)
+      return t->value;
+    current = current->next;
+  }
+
+  return NULL;
+}
+
+/**
+ * A function to fetch a specify value from a hash table by key.
+ *
+ * @param hash The hash table to search.
+ * @param key The key associated with the value to return
+ * @return Returns the data associated with the key or NULL if the key is not
+ * found.
+ */
+void *hash_get(Hash *hash, int key) {
+  unsigned int bucket = hash_code(hash, key);
+  Node *n = hash->buckets + bucket;
+  return (n->data) ? search(n, key) : NULL;
+}
+
+/**
+ * A function to set the value associated with a key
+ * in a hash table.
+ *
+ * @param hash The hash table to insert the key/value pair into
+ * @param key The key associated with the value to insert.
+ * @param value The value associated with the key to insert.
+ */
+void hash_set(Hash *hash, int key, void *value) {
+  unsigned int bucket = hash_code(hash, key);
+  Tuple *tuple = tuple_initialize(key, value);
+  Node *n = hash->buckets + bucket;
+
+  if (n->data)
+    list_add(n, tuple);
+  else
+    hash->buckets[bucket] = *list_initialize(tuple);
+}
+
+/**
+ * A function that pretty prints a key/value pair.
+ *
+ * @param data The Tuple to print.
+ */
+void print_tuple(void *data) {
+  Tuple *t = data;
+
+  if (t)
+    printf("(%d:%d)", t->key, t->value);
+  else
+    printf("(nil)");
+}
+
+/**
+ * Prints a visual representation of a hash table.
+ *
+ * @param hash The hash table to inspect
+ */
+void hash_inspect(Hash *hash) {
+  for (int i = 0; i < hash->size; i++) {
+    printf("%2d: ", i);
+    list_inspect(hash->buckets + i, print_tuple);
+  }
+}
src/02/04/hash.h
@@ -0,0 +1,11 @@
+#include "list.h"
+
+typedef struct {
+  Node *buckets;
+  int size;
+} Hash;
+
+Hash *hash_init(int buckets);
+void *hash_get(Hash *hash, int key);
+void hash_set(Hash *hash, int key, void *value);
+void hash_inspect(Hash *hash);
src/02/04/hash.rb
@@ -0,0 +1,61 @@
+class List
+  attr_reader :next, :data
+
+  def initialize(data)
+    @data = data
+  end
+
+  def add(data)
+    if self.next
+      self.next.add(data)
+    else
+      @next = self.class.new(data)
+    end
+  end
+
+  def search(&block)
+    return self if block.call(data)
+
+    @next&.search(&block)
+  end
+end
+
+class MHash
+  def initialize(size = 13)
+    @size = size
+    @buckets = Array.new(size)
+  end
+
+  def [](key)
+    bucket = bucket_for(key)
+    node = @buckets[bucket]
+    return if node.nil?
+
+    found = node.search do |item|
+      item[0] == key
+    end
+    return found.data[-1] if found
+  end
+
+  def []=(key, value)
+    bucket = bucket_for(key)
+    if @buckets[bucket]
+      @buckets[bucket].add([key, value])
+    else
+      @buckets[bucket] = List.new([key, value])
+    end
+  end
+
+  private
+
+  def bucket_for(key)
+    key % @size
+  end
+end
+
+h = MHash.new
+h[8] = 'hello'
+h[21] = 'jello'
+
+puts [8, h[8]].inspect
+puts [21, h[21]].inspect
src/02/04/hash_test.c
@@ -0,0 +1,80 @@
+#include "hash.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Describe(HashTable);
+BeforeEach(HashTable) {}
+AfterEach(HashTable) {}
+
+Ensure(HashTable, when_initializing_a_hash) {
+  Hash *hash = hash_init(13);
+
+  assert_that(hash, is_not_equal_to(NULL));
+}
+
+Ensure(HashTable, when_getting_a_value_for_a_key_that_has_not_been_inserted) {
+  Hash *hash = hash_init(13);
+
+  assert_that(hash_get(hash, 1), is_equal_to(NULL));
+}
+
+Ensure(HashTable, when_getting_a_values_for_a_key_that_has_been_inserted) {
+  Hash *hash = hash_init(13);
+  int key = 7;
+
+  hash_set(hash, key, (void *)100);
+  assert_that(hash_get(hash, key), is_equal_to(100));
+}
+
+Ensure(HashTable, when_a_hash_collision_occurs) {
+  Hash *hash = hash_init(13);
+
+  hash_set(hash, 8, (void *)80);
+  hash_set(hash, 21, (void *)210);
+
+  assert_that(hash_get(hash, 8), is_equal_to(80));
+  assert_that(hash_get(hash, 21), is_equal_to(210));
+}
+
+Ensure(HashTable, when_inserting_multiple_items_into_the_hash_table) {
+  Hash *hash = hash_init(13);
+  int items[] = {1, 5, 21, 26, 39, 14, 15, 16, 17, 18, 19, 20, 111, 145, 146};
+  int n = sizeof(items) / sizeof(int);
+
+  for (int i = 0; i < n; i++) {
+    int key = items[i];
+    long value = key * 10;
+    hash_set(hash, key, (void *)value);
+  }
+
+  for (int i = 0; i < n; i++) {
+    int key = items[i];
+    assert_that(hash_get(hash, key), is_equal_to(key * 10));
+  }
+}
+
+TestSuite *hash_table_tests() {
+  TestSuite *suite = create_test_suite();
+
+  add_test_with_context(suite, HashTable, when_initializing_a_hash);
+  add_test_with_context(
+      suite, HashTable,
+      when_getting_a_value_for_a_key_that_has_not_been_inserted);
+  add_test_with_context(suite, HashTable,
+                        when_getting_a_values_for_a_key_that_has_been_inserted);
+  add_test_with_context(suite, HashTable, when_a_hash_collision_occurs);
+  add_test_with_context(suite, HashTable,
+                        when_inserting_multiple_items_into_the_hash_table);
+  return suite;
+}
+
+extern TestSuite *list_tests();
+extern TestSuite *tuple_tests();
+
+int main(int argc, char **argv) {
+  TestSuite *suite = create_test_suite();
+  add_suite(suite, hash_table_tests());
+  add_suite(suite, list_tests());
+  add_suite(suite, tuple_tests());
+  return run_test_suite(suite, create_text_reporter());
+}
src/02/04/list.c
@@ -0,0 +1,86 @@
+#include "list.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Initializes a new node for a linked list.
+ *
+ * @param data The data to bind to the new node in the list.
+ * @return Returns a new linked list node
+ */
+Node *list_initialize(void *data) {
+  Node *node = malloc(sizeof(Node));
+  node->data = data;
+  node->next = NULL;
+  return node;
+}
+
+/**
+ * Adds a new item to the tail of a linked list
+ *
+ * @param head The head of a linked list
+ * @param data The data to add to the tail of a linked list
+ * @return Returns the new node tail node
+ */
+Node *list_add(Node *head, void *data) {
+  Node *tail;
+  Node *tmp = head;
+
+  while (tmp) {
+    if (!tmp->next)
+      break;
+    tmp = tmp->next;
+  }
+  tail = tmp;
+  tail->next = list_initialize(data);
+  return tail->next;
+}
+
+/**
+ * Returns a specific node by zero based index in a linked list.
+ *
+ * @param self the head of the linked list
+ * @param index the offset from the head of the node to return
+ * @return Returns the node at the specified offset or NULL.
+ */
+Node *list_get(Node *self, int index) {
+  if (!self || index < 0)
+    return NULL;
+
+  while (index > 0 && self) {
+    self = self->next;
+    index--;
+  }
+  return self;
+}
+
+/**
+ * Returns the total number of nodes in a linked list.
+ *
+ * @param head The head of a linked list
+ * @returns Returns the # of items in the list.
+ */
+int list_size(Node *head) {
+  int i = 0;
+  for (Node *tmp = head; tmp && tmp != NULL; tmp = tmp->next)
+    i++;
+  return i;
+}
+
+/**
+ * Prints a visual representation of a linked list.
+ *
+ * @param self The head of the linked list
+ * @param printer A callback function to invoke to print each item.
+ */
+void list_inspect(Node *self, Printer printer) {
+  if (!self)
+    return;
+
+  printf("[");
+  while (self) {
+    printer(self->data);
+    self = self->next;
+  }
+  printf("]\n");
+}
src/02/04/list.h
@@ -0,0 +1,11 @@
+typedef struct node {
+  struct node *next;
+  void *data;
+} Node;
+
+typedef void (*Printer)(void *);
+
+Node *list_initialize(void *data);
+Node *list_get(Node *from, int index);
+Node *list_add(Node *head, void *data);
+void list_inspect(Node *self, Printer printer);
src/02/04/list_test.c
@@ -0,0 +1,91 @@
+#include "list.h"
+#include <cgreen/cgreen.h>
+
+Describe(List);
+BeforeEach(List) {}
+AfterEach(List) {}
+
+Ensure(List, when_getting_head) {
+  Node *head = list_initialize((void *)100);
+  assert_that(list_get(head, 0), is_equal_to(head));
+  assert_that(list_get(head, 0)->data, is_equal_to(100));
+  free(head);
+}
+
+Ensure(List, when_getting_mid) {
+  Node *head = list_initialize((void *)100);
+
+  Node *mid = list_add(head, (void *)200);
+  list_add(head, (void *)300);
+
+  assert_that(list_get(head, 1), is_equal_to(mid));
+  assert_that(list_get(head, 1)->data, is_equal_to(200));
+
+  free(head);
+}
+
+Ensure(List, when_getting_tail) {
+  Node *head = list_initialize((void *)100);
+  Node *mid = list_add(head, (void *)200);
+  Node *tail = list_add(head, (void *)300);
+
+  assert_that(list_get(head, 0), is_equal_to(head));
+  assert_that(list_get(head, 0)->data, is_equal_to(100));
+
+  assert_that(list_get(head, 1), is_equal_to(mid));
+  assert_that(list_get(head, 1)->data, is_equal_to(200));
+
+  assert_that(list_get(head, 2), is_equal_to(tail));
+  assert_that(list_get(head, 2)->data, is_equal_to(300));
+
+  free(head);
+}
+
+Ensure(List, when_getting_from_empty_list) {
+  assert_that(list_get(NULL, 2), is_equal_to(NULL));
+}
+
+Ensure(List, when_getting_negative_index) {
+  Node *head = list_initialize((void *)100);
+
+  assert_that(list_get(head, -1), is_equal_to(NULL));
+
+  free(head);
+}
+
+Ensure(List, when_getting_index_out_of_range) {
+  Node *head = list_initialize((void *)100);
+
+  assert_that(list_get(head, 1), is_equal_to(NULL));
+
+  free(head);
+}
+
+struct Person {
+  int age;
+};
+
+Ensure(List, when_adding_a_custom_datatype) {
+  struct Person *item = malloc(sizeof(struct Person));
+  item->age = 36;
+  Node *head = list_initialize((void *)item);
+
+  Node *result = list_get(head, 0);
+  assert_that(result, is_equal_to(head));
+
+  struct Person *p = (struct Person *)result->data;
+  assert_that(p->age, is_equal_to(36));
+}
+
+TestSuite *list_tests() {
+  TestSuite *suite = create_test_suite();
+
+  add_test_with_context(suite, List, when_getting_head);
+  add_test_with_context(suite, List, when_getting_mid);
+  add_test_with_context(suite, List, when_getting_tail);
+  add_test_with_context(suite, List, when_getting_from_empty_list);
+  add_test_with_context(suite, List, when_getting_negative_index);
+  add_test_with_context(suite, List, when_getting_index_out_of_range);
+  add_test_with_context(suite, List, when_adding_a_custom_datatype);
+  return suite;
+}
src/02/04/main.c
@@ -0,0 +1,29 @@
+#include "hash.h"
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+  printf("=== COMP-272 - Assignment 02 - Question 04 ===\n");
+  Hash *hash = hash_init(13);
+  int items[] = {1, 5, 21, 26, 39, 14, 15, 16, 17, 18, 19, 20, 111, 145, 146};
+  int n = sizeof(items) / sizeof(int);
+
+  printf("Insert items into hash\n");
+  for (int i = 0; i < n; i++) {
+    int key = items[i];
+    long value = key * 10;
+    printf("(%d:%d) ", key, value);
+    hash_set(hash, key, (void *)value);
+  }
+
+  printf("\nInspect hash table\n");
+  hash_inspect(hash);
+
+  printf("Retrieve each item from the table\n");
+  for (int i = 0; i < n; i++) {
+    int key = items[i];
+    printf("(%d:%d) ", key, hash_get(hash, key));
+  }
+
+  printf("\nBye\n");
+  return 0;
+}
src/02/04/Makefile
@@ -0,0 +1,38 @@
+#!/usr/bin/make -f
+SHELL=/bin/sh
+
+CC=clang
+CFLAGS=-std=c99
+TEST_LIBS = -lcgreen
+
+BUILDDIR := build
+OBJS := $(addprefix $(BUILDDIR)/,hash.o list.o tuple.o)
+TEST_OBJS := $(addprefix $(BUILDDIR)/,hash_test.o list_test.o tuple_test.o)
+
+$(BUILDDIR)/%.o : %.c
+	$(COMPILE.c) $(OUTPUT_OPTION) $<
+
+.PHONY: all
+all: $(OBJS) $(BUILDDIR)/main.o
+	$(CC) $(OBJS) $(BUILDDIR)/main.o -o $(BUILDDIR)/program
+
+.PHONY: test
+test: $(OBJS) $(TEST_OBJS)
+	$(CC) $(OBJS) $(TEST_OBJS) $(TEST_LIBS) -o $(BUILDDIR)/test
+
+$(OBJS): | $(BUILDDIR)
+
+$(TEST_OBJS): | $(BUILDDIR)
+
+$(BUILDDIR):
+	mkdir $(BUILDDIR)
+
+.PHONY: clean
+clean:
+	rm -fr build
+
+run : all
+	./build/program
+
+run_test : test
+	cgreen-runner -c -v $(BUILDDIR)/test
src/02/04/README.md
@@ -0,0 +1,5 @@
+Implement a commonly used hash table in a program that handles collision using linear probing.
+
+Using (K mod 13) as the hash function, store the following elements in the table:
+
+{1, 5, 21, 26, 39, 14, 15, 16, 17, 18, 19, 20, 111, 145, 146}.
src/02/04/tuple.c
@@ -0,0 +1,23 @@
+#include "tuple.h"
+#include "stdlib.h"
+
+/**
+ * Initializes a new tuple bound to a key/value pair.
+ *
+ * @param key The key to bind to
+ * @param value The value to bind to
+ * @return Returns a new Tuple
+ */
+Tuple *tuple_initialize(int key, void *value) {
+  Tuple *tuple = malloc(sizeof(Tuple));
+  tuple->key = key;
+  tuple->value = value;
+  return tuple;
+}
+
+/**
+ * A destructor for a Tuple
+ *
+ * @param tuple The tuple to free
+ */
+void tuple_destroy(Tuple *tuple) { return free(tuple); }
src/02/04/tuple.h
@@ -0,0 +1,7 @@
+typedef struct {
+  int key;
+  void *value;
+} Tuple;
+
+Tuple *tuple_initialize(int key, void *value);
+void tuple_destroy(Tuple *tuple);
src/02/04/tuple_test.c
@@ -0,0 +1,23 @@
+#include "tuple.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Describe(Tuple);
+BeforeEach(Tuple) {}
+AfterEach(Tuple) {}
+
+Ensure(Tuple, when_initializing_a_tuple) {
+  Tuple *subject = tuple_initialize(21, (void *)100);
+
+  assert_that(subject->key, is_equal_to(21));
+  assert_that(subject->value, is_equal_to(100));
+
+  tuple_destroy(subject);
+}
+
+TestSuite *tuple_tests() {
+  TestSuite *suite = create_test_suite();
+
+  add_test_with_context(suite, Tuple, when_initializing_a_tuple);
+  return suite;
+}
src/02/05/btree.c
@@ -0,0 +1,157 @@
+#include "btree.h"
+#include "stack.h"
+#include <stdio.h>
+
+/**
+ * Prints a visual representation of a binary tree
+ *
+ * @param tree The tree or subtree to print
+ * @param level The level in the tree that the subtree belongs to
+ */
+static void inspect(BTree *tree, int level) {
+  if (!tree)
+    return;
+
+  for (int i = 0; i < level; i++)
+    printf("  ");
+
+  printf("%2d\n", tree->data);
+  inspect(tree->left, level + 1);
+  inspect(tree->right, level + 1);
+}
+
+/**
+ * Initializes a new instance of a binary tree.
+ *
+ * @param data The data to bind to the root of the new subtree.
+ * @return Returns the new subtree.
+ */
+BTree *btree_init(int data) {
+  BTree *tree = malloc(sizeof(BTree));
+  tree->left = NULL;
+  tree->right = NULL;
+  tree->data = data;
+  return tree;
+}
+
+/**
+ * Performs and caches the result of a pre order traversal
+ * on a binary tree. Cached results are stored in the root of
+ * the tree and not on each node of the tree.
+ *
+ * @param tree The subtree to perform the traversal on
+ */
+void btree_pre_order_number(BTree *tree) {
+  BTree *original = tree;
+  if (tree == NULL)
+    return;
+
+  Stack *stack = stack_init();
+  int i = 0;
+
+  stack_push(stack, tree);
+  while (stack_size(stack) > 0) {
+    tree = stack_pop(stack);
+    original->pre_order[i++] = tree->data;
+
+    if (tree->right != NULL)
+      stack_push(stack, tree->right);
+    if (tree->left != NULL)
+      stack_push(stack, tree->left);
+  }
+}
+
+/**
+ * Performs and caches the result of an in order traversal
+ * on a binary tree. Cached results are stored in the root of
+ * the tree and not on each node of the tree.
+ *
+ * @param root The subtree to perform the traversal on
+ */
+void btree_in_order_number(BTree *root) {
+  BTree *original = root;
+  if (root == NULL)
+    return;
+
+  Stack *stack = stack_init();
+  int i = 0;
+
+  while (true) {
+    if (root) {
+      stack_push(stack, root);
+      root = root->left;
+    } else {
+      if (stack_size(stack) == 0)
+        break;
+
+      root = stack_pop(stack);
+      original->in_order[i++] = root->data;
+      root = root->right;
+    }
+  }
+}
+
+/**
+ * Performs and caches the result of an post order traversal
+ * on a binary tree. Cached results are stored in the root of
+ * the tree and not on each node of the tree.
+ *
+ * @param root The subtree to perform the traversal on
+ */
+void btree_post_order_number(BTree *root) {
+  BTree *original = root;
+  if (root == NULL)
+    return;
+
+  Stack *s1 = stack_init();
+  Stack *s2 = stack_init();
+
+  stack_push(s1, root);
+
+  while (stack_size(s1) > 0) {
+    root = stack_pop(s1);
+    stack_push(s2, root);
+
+    if (root->left)
+      stack_push(s1, root->left);
+    if (root->right)
+      stack_push(s1, root->right);
+  }
+
+  int i = 0;
+  while (stack_size(s2) > 0) {
+    root = stack_pop(s2);
+    original->post_order[i++] = root->data;
+  }
+}
+
+/**
+ * Insert a new items into a binary tree.
+ *
+ * @param tree The tree to insert the data into.
+ * @param data The data to insert into the tree.
+ * @return Returns the new root of the tree.
+ */
+BTree *btree_insert(BTree *tree, int data) {
+  if (!tree)
+    return btree_init(data);
+
+  if (data <= tree->data)
+    if (tree->left)
+      btree_insert(tree->left, data);
+    else
+      tree->left = btree_init(data);
+  else if (tree->right)
+    btree_insert(tree->right, data);
+  else
+    tree->right = btree_init(data);
+
+  return tree;
+}
+
+/**
+ * Prints a visual representation of a binary tree.
+ *
+ * @param tree The subtree to inspect.
+ */
+void btree_inspect(BTree *tree) { inspect(tree, 0); }
src/02/05/btree.h
@@ -0,0 +1,18 @@
+#include <stdlib.h>
+#include <stdbool.h>
+
+typedef struct btree_node {
+  struct btree_node *left;
+  struct btree_node *right;
+  int pre_order[32];
+  int in_order[32];
+  int post_order[32];
+  int data;
+} BTree;
+
+BTree *btree_init(int data);
+BTree *btree_insert(BTree *root, int data);
+void btree_in_order_number(BTree *tree);
+void btree_inspect(BTree *tree);
+void btree_post_order_number(BTree *tree);
+void btree_pre_order_number(BTree *tree);
src/02/05/btree_test.c
@@ -0,0 +1,223 @@
+#include "btree.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Describe(BinaryTree);
+BeforeEach(BinaryTree) {}
+AfterEach(BinaryTree) {}
+
+Ensure(BinaryTree, when_the_tree_is_NULL) {
+  BTree *tree = btree_insert(NULL, 10);
+
+  assert_that(tree, is_not_equal_to(NULL));
+  assert_that(tree->data, is_equal_to(10));
+}
+
+Ensure(BinaryTree,
+       when_the_tree_has_a_single_node_it_returns_the_items_in_order) {
+  BTree *tree = btree_insert(NULL, 10);
+
+  btree_in_order_number(tree);
+
+  assert_that(tree->in_order[0], is_equal_to(10));
+}
+
+Ensure(BinaryTree,
+       when_the_tree_has_multiple_levels_it_returns_the_items_in_order) {
+  BTree *tree = btree_insert(NULL, 10);
+
+  btree_insert(tree, 5);
+  btree_insert(tree, 15);
+  btree_insert(tree, 7);
+  btree_insert(tree, 12);
+  btree_insert(tree, 18);
+  btree_insert(tree, 3);
+
+  btree_in_order_number(tree);
+
+  assert_that(tree->in_order[0], is_equal_to(3));
+  assert_that(tree->in_order[1], is_equal_to(5));
+  assert_that(tree->in_order[2], is_equal_to(7));
+  assert_that(tree->in_order[3], is_equal_to(10));
+  assert_that(tree->in_order[4], is_equal_to(12));
+  assert_that(tree->in_order[5], is_equal_to(15));
+  assert_that(tree->in_order[6], is_equal_to(18));
+}
+
+Ensure(BinaryTree,
+       when_the_tree_has_multiple_levels_it_returns_the_items_in_pre_order) {
+  BTree *tree = btree_insert(NULL, 10);
+
+  btree_insert(tree, 5);
+  btree_insert(tree, 15);
+  btree_insert(tree, 7);
+  btree_insert(tree, 12);
+  btree_insert(tree, 18);
+  btree_insert(tree, 3);
+  /*
+      10
+    /    \
+  5      15
+ /  \    /  \
+3    7  12   18
+   */
+
+  btree_pre_order_number(tree);
+
+  assert_that(tree->pre_order[0], is_equal_to(10));
+  assert_that(tree->pre_order[1], is_equal_to(5));
+  assert_that(tree->pre_order[2], is_equal_to(3));
+  assert_that(tree->pre_order[3], is_equal_to(7));
+  assert_that(tree->pre_order[4], is_equal_to(15));
+  assert_that(tree->pre_order[5], is_equal_to(12));
+  assert_that(tree->pre_order[6], is_equal_to(18));
+}
+
+Ensure(BinaryTree,
+       when_the_tree_has_multiple_levels_it_returns_the_items_in_post_order) {
+  BTree *tree = btree_insert(NULL, 10);
+
+  btree_insert(tree, 5);
+  btree_insert(tree, 15);
+  btree_insert(tree, 7);
+  btree_insert(tree, 12);
+  btree_insert(tree, 18);
+  btree_insert(tree, 3);
+  /*
+      10
+    /    \
+  5      15
+ /  \    /  \
+3    7  12   18
+   */
+
+  btree_post_order_number(tree);
+
+  assert_that(tree->post_order[0], is_equal_to(3));
+  assert_that(tree->post_order[1], is_equal_to(7));
+  assert_that(tree->post_order[2], is_equal_to(5));
+  assert_that(tree->post_order[3], is_equal_to(12));
+  assert_that(tree->post_order[4], is_equal_to(18));
+  assert_that(tree->post_order[5], is_equal_to(15));
+  assert_that(tree->post_order[6], is_equal_to(10));
+}
+
+Ensure(
+    BinaryTree,
+    when_inserting_an_item_less_than_the_root_in_a_tree_it_creates_a_node_on_the_left_side) {
+  BTree *tree = btree_init(10);
+  btree_insert(tree, -5);
+
+  assert_that(tree->left, is_not_equal_to(NULL));
+  assert_that(tree->left->data, is_equal_to(-5));
+}
+
+Ensure(
+    BinaryTree,
+    when_inserting_an_item_greater_than_the_root_in_a_tree_it_creates_a_node_on_the_right_side) {
+  BTree *tree = btree_init(10);
+
+  btree_insert(tree, 16);
+
+  assert_that(tree->right, is_not_equal_to(NULL));
+  assert_that(tree->right->data, is_equal_to(16));
+}
+
+Ensure(
+    BinaryTree,
+    when_inserting_an_item_equal_to_the_root_in_a_tree_it_creates_a_node_on_the_left_side) {
+  BTree *tree = btree_init(10);
+
+  btree_insert(tree, 10);
+
+  assert_that(tree->left, is_not_equal_to(NULL));
+  assert_that(tree->left->data, is_equal_to(10));
+}
+
+Ensure(
+    BinaryTree,
+    when_inserting_multiple_items_into_a_tree_it_inserts_in_the_correct_position) {
+  BTree *tree = btree_insert(NULL, 10);
+
+  btree_insert(tree, -5);
+  btree_insert(tree, 16);
+
+  assert_that(tree->data, is_equal_to(10));
+  assert_that(tree->left->data, is_equal_to(-5));
+  assert_that(tree->right->data, is_equal_to(16));
+
+  btree_insert(tree, -8);
+
+  assert_that(tree->left->left, is_not_equal_to(NULL));
+  assert_that(tree->left->left->data, is_equal_to(-8));
+
+  btree_insert(tree, 7);
+
+  assert_that(tree->left->right, is_not_equal_to(NULL));
+  assert_that(tree->left->right->data, is_equal_to(7));
+
+  btree_insert(tree, 18);
+
+  assert_that(tree->right->right, is_not_equal_to(NULL));
+  assert_that(tree->right->right->data, is_equal_to(18));
+
+  btree_insert(tree, 6);
+
+  assert_that(tree->left->right->left, is_not_equal_to(NULL));
+  assert_that(tree->left->right->left->data, is_equal_to(6));
+}
+
+Ensure(
+    BinaryTree,
+    when_inserting_items_described_in_the_assignment_it_inserts_in_the_expected_position_in_the_tree) {
+  BTree *tree = btree_insert(NULL, 1);
+  tree = btree_insert(tree, 5);
+  tree = btree_insert(tree, 2);
+  tree = btree_insert(tree, 4);
+  tree = btree_insert(tree, 3);
+
+  assert_that(tree, is_not_equal_to(NULL));
+}
+
+TestSuite *btree_tests() {
+  TestSuite *suite = create_test_suite();
+  add_test_with_context(suite, BinaryTree, when_the_tree_is_NULL);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_the_tree_has_a_single_node_it_returns_the_items_in_order);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_the_tree_has_multiple_levels_it_returns_the_items_in_order);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_the_tree_has_multiple_levels_it_returns_the_items_in_pre_order);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_the_tree_has_multiple_levels_it_returns_the_items_in_post_order);
+
+  add_test_with_context(
+      suite, BinaryTree,
+      when_inserting_an_item_less_than_the_root_in_a_tree_it_creates_a_node_on_the_left_side);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_inserting_an_item_greater_than_the_root_in_a_tree_it_creates_a_node_on_the_right_side);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_inserting_an_item_equal_to_the_root_in_a_tree_it_creates_a_node_on_the_left_side);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_inserting_multiple_items_into_a_tree_it_inserts_in_the_correct_position);
+  add_test_with_context(
+      suite, BinaryTree,
+      when_inserting_items_described_in_the_assignment_it_inserts_in_the_expected_position_in_the_tree);
+  return suite;
+}
+
+extern TestSuite *stack_tests();
+
+int main(int argc, char **argv) {
+  TestSuite *suite = create_test_suite();
+  add_suite(suite, btree_tests());
+  add_suite(suite, stack_tests());
+  return run_test_suite(suite, create_text_reporter());
+}
src/02/05/main.c
@@ -0,0 +1,40 @@
+#include "btree.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+  printf("=== COMP-272 - Assignment 02 - Question 05 ===\n");
+  BTree *tree = btree_insert(NULL, 10);
+  btree_insert(tree, 5);
+  btree_insert(tree, 15);
+  btree_insert(tree, 7);
+  btree_insert(tree, 12);
+  btree_insert(tree, 18);
+  btree_insert(tree, 3);
+  btree_inspect(tree);
+
+  btree_pre_order_number(tree);
+  btree_in_order_number(tree);
+  btree_post_order_number(tree);
+
+  printf("Pre order traversal:\n");
+  for (int i = 0; i < 32; i++)
+    printf("%d ", tree->pre_order[i]);
+  printf("\n");
+  printf("\n");
+
+  printf("In order traversal:\n");
+  for (int i = 0; i < 32; i++)
+    printf("%d ", tree->in_order[i]);
+  printf("\n");
+  printf("\n");
+
+  printf("Post order traversal:\n");
+  for (int i = 0; i < 32; i++)
+    printf("%d ", tree->post_order[i]);
+  printf("\n");
+  printf("\n");
+
+  printf("Bye\n");
+  return 0;
+}
src/02/05/Makefile
@@ -0,0 +1,38 @@
+#!/usr/bin/make -f
+SHELL=/bin/sh
+
+CC=clang
+CFLAGS=-std=c99
+TEST_LIBS = -lcgreen
+
+BUILDDIR := build
+OBJS := $(addprefix $(BUILDDIR)/,btree.o stack.o)
+TEST_OBJS := $(addprefix $(BUILDDIR)/,btree_test.o stack_test.o)
+
+$(BUILDDIR)/%.o : %.c
+	$(COMPILE.c) $(OUTPUT_OPTION) $<
+
+.PHONY: all
+all: $(OBJS) $(BUILDDIR)/main.o
+	$(CC) $(OBJS) $(BUILDDIR)/main.o -o $(BUILDDIR)/program
+
+.PHONY: test
+test: $(OBJS) $(TEST_OBJS)
+	$(CC) $(OBJS) $(TEST_OBJS) $(TEST_LIBS) -o $(BUILDDIR)/test
+
+$(OBJS): | $(BUILDDIR)
+
+$(TEST_OBJS): | $(BUILDDIR)
+
+$(BUILDDIR):
+	mkdir $(BUILDDIR)
+
+.PHONY: clean
+clean:
+	rm -fr build
+
+run : all
+	./build/program
+
+run_test : test
+	cgreen-runner -c -v $(BUILDDIR)/test
src/02/05/README.md
@@ -0,0 +1,3 @@
+Create a subclass of `BinaryTree` whose nodes have fields for storing preorder, post-order, and in-order numbers.
+Write methods `preOrderNumber()`, `inOrderNumber()`, and `postOrderNumbers()` that assign these numbers correctly.
+These methods should each run in `O(n)` time.
src/02/05/stack.c
@@ -0,0 +1,52 @@
+#include "stack.h"
+#include <stdlib.h>
+
+Node *node_init(void *data) {
+  Node *node = malloc(sizeof(Node));
+  node->next = NULL;
+  node->data = data;
+  return node;
+}
+
+Stack *stack_init() {
+  Stack *stack = malloc(sizeof(Stack));
+  stack->head = NULL;
+  return stack;
+}
+
+int stack_size(Stack *self) {
+  if (!self || !self->head)
+    return 0;
+
+  int count = 0;
+  Node *current = self->head;
+  while (current) {
+    ++count;
+    current = current->next;
+  }
+
+  return count;
+}
+
+void *stack_peek(Stack *self) {
+  if (self->head)
+    return self->head->data;
+  return NULL;
+}
+
+void stack_push(Stack *stack, void *data) {
+  Node *node = node_init(data);
+  node->next = stack->head;
+  stack->head = node;
+}
+
+void *stack_pop(Stack *self) {
+  if (self->head) {
+    Node *tmp = self->head;
+    void *data = tmp->data;
+    self->head = self->head->next;
+    free(tmp);
+    return data;
+  }
+  return NULL;
+}
src/02/05/stack.h
@@ -0,0 +1,14 @@
+typedef struct node {
+  struct node *next;
+  void *data;
+} Node;
+
+typedef struct {
+  Node *head;
+} Stack;
+
+Stack *stack_init();
+void *stack_peek(Stack *self);
+int stack_size(Stack *self);
+void stack_push(Stack *self, void *data);
+void *stack_pop(Stack *self);
src/02/05/stack_test.c
@@ -0,0 +1,65 @@
+#include "stack.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Describe(Stack);
+BeforeEach(Stack) {}
+AfterEach(Stack) {}
+
+Ensure(Stack, when_pushing_an_item_on_to_a_stack) {
+  Stack *stack = stack_init();
+
+  stack_push(stack, (void *)10);
+
+  assert_that(stack_size(stack), is_equal_to(1));
+  assert_that(stack_peek(stack), is_equal_to(10));
+}
+
+Ensure(Stack, when_pushing_multiple_items_on_to_a_stack) {
+  Stack *stack = stack_init();
+
+  stack_push(stack, (void *)20);
+  stack_push(stack, (void *)10);
+  stack_push(stack, (void *)50);
+
+  assert_that(stack_size(stack), is_equal_to(3));
+  assert_that(stack_peek(stack), is_equal_to(50));
+}
+
+Ensure(Stack, when_pushing_a_custom_type_on_to_a_stack) {
+  typedef struct {
+  } Item;
+
+  Stack *stack = stack_init();
+  Item *item = malloc(sizeof(Item));
+
+  stack_push(stack, item);
+
+  assert_that(stack_size(stack), is_equal_to(1));
+  assert_that(stack_peek(stack), is_equal_to(item));
+  assert_that(stack_pop(stack), is_equal_to(item));
+}
+
+Ensure(Stack, when_popping_an_item_off_of_a_stack) {
+  Stack *stack = stack_init();
+
+  stack_push(stack, (void *)20);
+  stack_push(stack, (void *)10);
+  stack_push(stack, (void *)50);
+
+  void *result = stack_pop(stack);
+
+  assert_that(stack_size(stack), is_equal_to(2));
+  assert_that(stack_peek(stack), is_equal_to(10));
+  assert_that(result, is_equal_to(50));
+}
+
+TestSuite *stack_tests() {
+  TestSuite *suite = create_test_suite();
+  add_test_with_context(suite, Stack, when_pushing_an_item_on_to_a_stack);
+  add_test_with_context(suite, Stack,
+                        when_pushing_multiple_items_on_to_a_stack);
+  add_test_with_context(suite, Stack, when_pushing_a_custom_type_on_to_a_stack);
+  add_test_with_context(suite, Stack, when_popping_an_item_off_of_a_stack);
+  return suite;
+}
src/02/README.md
@@ -0,0 +1,568 @@
+# Learning Profile for Assignment #2 - Computer Science 272: Data Structures and Algorithms
+
+Name: Mo Khan
+Student ID: 3431709
+
+## Question 1
+### Problem Statement
+
+Design an algorithm for the following operations for a binary tree BT, and show the worst-case running times for each implementation:
+* preorderNext(x): return the node visited after node x in a pre-order traversal of BT.
+* postorderNext(x): return the node visited after node x in a post-order traversal of BT.
+* inorderNext(x): return the node visited after node x in an in-order traversal of BT.
+
+### Description of the Code
+
+I chose to implement the binary tree traversal using
+a Visitor design pattern. The `traverse` function
+accepts a binary tree node, a callback function and
+the type of traversal to perform.
+
+The traversal uses recursion to visit each node in the
+binary tree in linear time. The space complexity is determined
+by the size of the tree because each recursive call
+adds another frame to the call stack.
+
+### Errors and Warnings
+
+I wrote unit tests to to cover several different happy path
+scenarios and to cover the base case conditions of the
+recursive function.
+
+```bash
+モ cd 01/ && make clean && make test && ./build/test
+rm -fr build
+mkdir build
+clang    -c -o build/binary_tree.o binary_tree.c
+clang    -c -o build/binary_tree_test.o binary_tree_test.c
+clang build/binary_tree.o build/binary_tree_test.o -lcgreen -o build/test
+Running "main" (21 tests)...
+  "binary_tree_tests": 72 passes in 10ms.
+  Completed "main": 72 passes in 10ms.
+```
+
+### Sample Input and Output
+
+The file `01/main.c` includes a small program that provides
+and example of the tree traversal. It starts by print out
+the binary tree to the console then prints the order each
+node is visited during each type of traversal.
+
+```bash
+モ cd 01/ && make clean && make && ./build/program
+rm -fr build
+mkdir build
+clang    -c -o build/binary_tree.o binary_tree.c
+clang    -c -o build/main.o main.c
+clang build/binary_tree.o build/main.o -o build/program
+=== COMP-272 - Assignment 02 - Question 01 ===
+(100)
+  (200)
+    (400)
+    (500)
+  (300)
+
+=== Pre order traversal ===
+100 200 400 500 300
+
+=== In order traversal ===
+400 200 500 100 300
+
+=== Post order traversal ===
+400 500 200 300 100
+```
+
+### Discussion
+
+This version of the traversal requires the calling code
+to capture each node that is visited during the traversal.
+This ensures that the traversal operates in O(n) time
+but allows the calling code to cache the result of the traversal
+in a way that makes sense for it.
+
+## Question 2
+### Problem Statement
+
+Design a recursive linear-time algorithm that
+tests whether a binary tree satisfies the
+search tree order property at every node.
+
+### Description of the Code
+
+To determine if a binary tree satisfies the binary
+search tree order property I needed to check each
+node in the binary tree to make sure that the item
+in the left side of the node is less than the node itself
+and that the item in the right side of the node is
+greater than itself. Each descendant node must also be
+greater or less than each ancestor node depending on which side
+of the tree that node is relative to the ancestor.
+
+To perform this check I kept track of the minimum
+and maximum values that any node can be while traversing
+down the tree.
+
+For example, when traversing down a left sub tree each
+node in the left sub tree must be between the minimum
+value and the current node. When traversing down the
+right subtree each node must be between the value in
+the current node and the maximum value.
+
+To kick start the recursive call I specified an arbitrary
+min and max values that matched the boundary of the size of
+the integer. So a range (2^32/2 * -1) and (2^32/2 - 1) was used.
+
+The base case for the recursive call is when the subtree
+that is visited is a NULL.
+
+### Errors and Warnings
+
+I wrote unit tests to test the happy day scenarios, the base
+case and a couple of edge cases.
+
+```bash
+モ make clean && make test && ./build/test
+rm -fr build
+mkdir build
+clang    -c -o build/btree.o btree.c
+clang    -c -o build/btree_test.o btree_test.c
+clang build/btree.o build/btree_test.o -lcgreen -o build/test
+Running "main" (7 tests)...
+  "binary_search_tree_tests": 7 passes in 3ms.
+  Completed "main": 7 passes in 4ms.
+```
+
+A full list of tests cases can be found in `02/*_test.c`.
+
+### Sample Input and Output
+
+To make it easier to see that the checks are working as
+expected, I included a program in `02/main.c` that will
+build a binary search tree and a regular binary tree and
+check to see if either matches the properties of a binary
+search tree.
+
+Sample output can be seen below:
+
+```bash
+モ cd 02/ && make clean && make && ./build/program
+rm -fr build
+mkdir build
+clang    -c -o build/btree.o btree.c
+clang    -c -o build/main.o main.c
+clang build/btree.o build/main.o -o build/program
+=== COMP-272 - Assignment 02 - Question 02 ===
+Binary Search Tree
+---------
+10
+  -5
+    -10
+     5
+  25
+    23
+    36
+Is a binary search tree? y
+
+Binary Tree
+---------
+10
+   0
+    -1
+    21
+  25
+    16
+    32
+Is a binary search tree? n
+
+Bye
+```
+
+### Discussion
+
+The recursive version of the check operates in
+`O(n)` time and `O(n)` space. The space is due
+to the allocation of a stack frame for each
+recursive call in the call stack. An iterative
+version of this same algorithm would also
+operate in linear time but could benefit
+from `O(1)` space by using pointers.
+
+## Question 3
+### Problem Statement
+
+Illustrate what happens when the sequence 1, 5, 2, 4, 3 is added to an empty
+ScapegoatTree, and show where the credits described in the proof of Lemma 8.3 go,
+and how they are used during this sequence of additions.
+
+In an unbalanced binary tree the insertion of `1,5,2,4,3` would
+look like the following:
+
+```plaintext
+Insert 1:
+           (1)
+
+Insert 5:
+           (1)
+              \
+              (5)
+
+Insert 2:
+           (1)
+              \
+              (5)
+              /
+            (2)
+
+
+Insert 4:
+           (1)
+              \
+              (5)
+              /
+            (2)
+              \
+              (4)
+
+Insert 3:
+
+           (1)
+              \
+              (5)
+              /
+            (2)
+              \
+              (4)
+              /
+            (3)
+```
+
+The above diagram illustrates some negative consequences
+for having an unbalanced binary tree. This includes needing
+to visit more nodes than necessary to perform a search and
+can lead to worst case searches of `O(n)` time.
+
+For example:
+
+```plaintext
+  (1)
+    \
+    (2)
+      \
+      (3)
+        \
+        (4)
+          \
+          (5)
+```
+
+The scapegoat tree allows the binary tree to remain
+balanced so that searches can operate in `O(logn)` time.
+It also does this by maintaining constant space `O(1)`.
+Other, balanced binary search tree algorithms like the
+AVL tree or Red-Black tree typically require adding additional
+data to each node in the tree in order to keep the tree balanced.
+
+The insertion of `1,5,2,4,3` into a scapegoat tree would look
+like the following:
+
+```plaintext
+Insert 1:
+           (1)
+
+Insert 5:
+           (1)     1/2
+              \
+              (5)
+
+Insert 2:
+           (1)     2/3 > 2/3: false
+              \
+              (5)  1/2 > 2/3: false
+              /
+            (2)
+
+Insert 4:
+           (1)     3/4 > 2/3: true (scapegoat)
+              \
+              (5)  2/3 > 2/3: false
+              /
+            (2)    1/2 > 2/3: false
+              \
+              (4)
+```
+
+The next step is to rebalance from the scapegoat node.
+
+Rebalance:
+
+1. collect nodes in sorted order: [1,2,4,5]
+1. find new root: size/2 = 4/2 = 2
+1. 2 is the second node and is selected as the new root
+1. [1] is moved to the left subtree
+1. [4,5] are moved to the right subtree
+
+```plaintext
+          (2)
+         /   \
+       (1)   (4)
+               \
+               (5)
+
+Insert 3:
+
+          (2)       3/5 > 2/3: false
+         /   \
+       (1)   (4)    1/3 > 2/3: false
+            /   \
+          (3)   (5)
+```
+
+### Description of the Code
+
+The code implements the regular binary tree insertion
+but it does not implement the rebalancing.
+
+### Errors and Warnings
+
+The tests can be viewed in `03/*_test.c`.
+
+```bash
+モ make clean && make test && ./build/test
+rm -fr build
+mkdir build
+clang    -c -o build/btree.o btree.c
+clang    -c -o build/btree_test.o btree_test.c
+clang build/btree.o build/btree_test.o -lcgreen -o build/test
+Running "main" (6 tests)...
+ 1
+   5
+     2
+       4
+         3
+  "binary_search_tree_tests": 20 passes in 3ms.
+Completed "main": 20 passes in 3ms.
+```
+
+### Sample Input and Output
+
+The example program in `03/main.c` displays
+a visual representation of an unbalanced and
+a balanced binary search tree.
+
+```bash
+モ cd 03/ && make clean && make && ./build/program
+rm -fr build
+mkdir build
+clang    -c -o build/btree.o btree.c
+clang    -c -o build/main.o main.c
+clang build/btree.o build/main.o -o build/program
+=== COMP-272 - Assignment 02 - Question 03 ===
+Tree 1: unbalanced tree
+ 1
+   5
+     2
+       4
+         3
+Tree 2: balanced tree
+ 3
+   2
+     1
+   4
+     5
+Bye
+```
+
+### Discussion
+
+Rebalancing a tree can be a tricky operation and
+it can slow down insertions into the tree.
+During rebalancing it is important to choose
+a new root to reduce too much rebalancing operations.
+
+## Question 4
+### Problem Statement
+
+Implement a commonly used hash table in a program that handles collision using linear probing.
+
+Using (K mod 13) as the hash function, store the following elements in the table:
+
+{1, 5, 21, 26, 39, 14, 15, 16, 17, 18, 19, 20, 111, 145, 146}.
+
+### Description of the Code
+
+To implement a hash table I chose to store
+a linked list in each bucket and perform a
+linear, `O(n)`, scan to find the correct node.
+
+This could have been optimized further by using
+a balanced binary search tree and performing
+a binary search to find the correct node
+when a collision occurs.
+
+Each node in the linked list is stored as a
+2-Tuple (two-ple) to store the key and associated
+value.
+
+### Errors and Warnings
+
+Unit tests for the Tuple, List and Btree can
+be found in the corresponding files with a `04/*_test.c`
+suffix.
+
+```bash
+モ cd 04 && make clean && make test && ./build/test
+rm -fr build
+mkdir build
+clang -std=c99   -c -o build/hash.o hash.c
+clang -std=c99   -c -o build/list.o list.c
+clang -std=c99   -c -o build/tuple.o tuple.c
+clang -std=c99   -c -o build/hash_test.o hash_test.c
+clang -std=c99   -c -o build/list_test.o list_test.c
+clang -std=c99   -c -o build/tuple_test.o tuple_test.c
+clang build/hash.o build/list.o build/tuple.o build/hash_test.o build/list_test.o build/tuple_test.o -lcgreen -o build/test
+Running "main" (13 tests)...
+  "hash_table_tests": 20 passes in 2ms.
+  "list_tests": 15 passes in 3ms.
+  "tuple_tests": 2 passes in 1ms.
+Completed "main": 37 passes in 6ms.
+```
+
+### Sample Input and Output
+
+An example program is included in `04/main.c`
+that prints a visual representation of the
+content of the hash table.
+
+```bash
+モ cd 04 && make clean && make && ./build/program
+rm -fr build
+mkdir build
+clang -std=c99   -c -o build/hash.o hash.c
+clang -std=c99   -c -o build/list.o list.c
+clang -std=c99   -c -o build/tuple.o tuple.c
+clang -std=c99   -c -o build/main.o main.c
+clang build/hash.o build/list.o build/tuple.o build/main.o -o build/program
+=== COMP-272 - Assignment 02 - Question 04 ===
+Insert items into hash
+(1:10) (5:50) (21:210) (26:260) (39:390) (14:140) (15:150) (16:160) (17:170) (18:180) (19:190) (20:200) (111:1110) (145:1450) (146:1460)
+Inspect hash table
+ 0: [(26:260)(39:390)]
+ 1: [(1:10)(14:140)]
+ 2: [(15:150)(145:1450)]
+ 3: [(16:160)(146:1460)]
+ 4: [(17:170)]
+ 5: [(5:50)(18:180)]
+ 6: [(19:190)]
+ 7: [(20:200)(111:1110)]
+ 8: [(21:210)]
+ 9: [(nil)]
+10: [(nil)]
+11: [(nil)]
+12: [(nil)]
+Retrieve each item from the table
+(1:10) (5:50) (21:210) (26:260) (39:390) (14:140) (15:150) (16:160) (17:170) (18:180) (19:190) (20:200) (111:1110) (145:1450) (146:1460)
+Bye
+```
+
+### Discussion
+
+Choosing to back the hash table with a linked
+list made it easier to implement the code but
+it does come with the cost of time complexity.
+
+By using a balanced binary search tree the
+time to look up a key would have been
+`O(1)` (compute hash) + `O(logn)` i.e. `O(logn)`.
+Using, a linked list changes the time
+complexity to `O(1)` + `O(n)` i.e. `O(n)`.
+
+## Question 5
+### Problem Statement
+
+Create a subclass of `BinaryTree` whose nodes have fields for storing preorder,
+post-order, and in-order numbers.
+Write methods `preOrderNumber()`, `inOrderNumber()`, and `postOrderNumbers()`
+that assign these numbers correctly.
+These methods should each run in `O(n)` time.
+
+### Description of the Code
+
+I chose to write this assignment in `C`, so the notion
+of subclassing and inheritance does not apply.
+
+To accommodate the problem statement, I updated the
+binary tree struct to include an integer array
+that can store up to 32 entries. Each array
+includes a cached copy of the traversal order
+for pre order, in order and post order traversals.
+
+To fill the cache, the function `btree_(pre|in|post)_order_number`
+must be called. The cached traversal is stored
+in the root of the tree that is provided.
+
+I chose to use a Stack to perform the traversal in
+an iterative way. In previous implementations of the
+traversal algorithm for the other questsions in this
+assignment I chose to use recursion. This implementation
+explicitly uses a stack instead of implicitly through
+stack frames in the call stack.
+
+### Errors and Warnings
+
+Unit tests for this can be found in `05/*_test.c`.
+
+```bash
+モ make clean && make test && ./build/test
+rm -fr build
+mkdir build
+clang -std=c99   -c -o build/btree.o btree.c
+clang -std=c99   -c -o build/stack.o stack.c
+clang -std=c99   -c -o build/btree_test.o btree_test.c
+clang -std=c99   -c -o build/stack_test.o stack_test.c
+clang build/btree.o build/stack.o build/btree_test.o build/stack_test.o -lcgreen -o build/test
+Running "main" (14 tests)...
+  "btree_tests": 42 passes in 5ms.
+  "stack_tests": 10 passes in 2ms.
+Completed "main": 52 passes in 7ms.
+```
+
+### Sample Input and Output
+
+A sample program can be found in `05/main.c` that
+prints out the traversal for an example tree.
+
+```bash
+モ cd 05 && make clean && make && ./build/program
+rm -fr build
+mkdir build
+clang -std=c99   -c -o build/btree.o btree.c
+clang -std=c99   -c -o build/stack.o stack.c
+clang -std=c99   -c -o build/main.o main.c
+clang build/btree.o build/stack.o build/main.o -o build/program
+=== COMP-272 - Assignment 02 - Question 05 ===
+10
+   5
+     3
+     7
+  15
+    12
+    18
+Pre order traversal:
+10 5 3 7 15 12 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+In order traversal:
+3 5 7 10 12 15 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+Post order traversal:
+3 7 5 12 18 15 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+Bye
+```
+
+### Discussion
+
+Allocating space for 32 values for the pre order, in order and post order
+representation for each node in a binary tree is quite wasteful.
+
+An alternative implementation might have returned a linked list
+instead of storing this data in an array on each node.
.gitignore
@@ -1,3 +1,5 @@
 *.o
 program
 build/
+*.tar.gz
+*.zip
Makefile
@@ -4,6 +4,9 @@ objects := $(shell find src -mindepth 2 -maxdepth 2 -type d)
 run :
 	for i in $(objects); do cd $$i && make clean run && cd -; done
 
+clean :
+	for i in $(objects); do cd $$i && make clean && cd -; done
+
 test :
 	for i in $(objects); do cd $$i && make clean run_test && cd -; done
 
README.md
@@ -1,5 +1,15 @@
 # Computer Science 272 (COMP-272): Data Structures and Algorithms
 
+COMP 272 covers analysis and design of fundamental data structures and engages
+learners to use data structures as tools to algorithmically design efficient
+computer programs that will cope with the complexity of actual applications.
+
+The course focuses on basic and essential topics in data structures,
+including array-based lists, linked lists, skiplists, hash tables,
+recursion, binary trees, scapegoat trees, red–black trees, heaps,
+sorting algorithms, graphs, and binary trie.
+
+* [Course Website](https://www.athabascau.ca/syllabi/comp/comp272.php)
 * [Assignments](./doc/assignments)
 * [Units](./doc/unit)