Comparing changes
2.0.0
→
3.0.0
92 commits
29 files changed
Commits
36d01ed
feat: prove that height of binary tree is greater than or equal to log2(k) where k is the # of leaves in the tree
2020-09-27 01:39:48
e7fc8f9
feat: implement backtracking algorithm to visit each edge in both directions
2020-09-26 23:05:39
Changed files (29)
src
doc/unit/09/README.md
@@ -0,0 +1,253 @@
+# 2-4 Trees
+
+* is a rooted tree with the following properties:
+
+* height: all leaves have the same depth
+* degree: every internal node has 2, 3 or 4 children.
+
+lemma:
+
+> A 2-4 tree with n leaves has height at most log n.
+
+# Red-Black Trees
+
+[Lecture Video](https://www.youtube.com/watch?v=JMZkuYa04tY)
+
+* A binary search tree with logarithmic height.
+
+1. tree with `n` values has a height of most 2logn
+1. The `add(x)` and `remove(x)` operations on a red-black tree run in `O(logn)` worst case time.
+1. The amortized number of rotations performed during an `add(x)` or `remove(x)` operation is constant.
+
+Each node, `u`, has a colour which is either `red` or `black`.
+
+* red: is represented by the value 0.
+* black: is represented by the value 1.
+
+A red-black tree implements the SSet interface and supports
+operations `add(x)`, `remove(x)`, and `find(x)` in O(logn) worst-case time
+per operation.
+
+
+```java
+class Node<T> extends BSTNode<Node<T>, T> {
+ byte colour;
+
+ void flipRight(Node<T> u) {
+ swapColours(u, u.left);
+ rotateRight(u);
+ }
+
+ void flipLeft(Node<T> u) {
+ swapColours(u, u.right);
+ rotateLeft(u);
+ }
+
+ boolean add(T x) {
+ Node<T> u = newNode(x);
+ u.colour = red;
+ boolean added = add(u);
+ if (added)
+ addFixup(u);
+ return added;
+ }
+
+ void addFixup(Node<T> u) {
+ while (u.colour == red) {
+ if (u == r) {
+ u.colour = black;
+ return;
+ }
+ Node<T> w = u.parent;
+ if (w.left.colour == black) {
+ flipLeft(w);
+ u = w;
+ w = u.parent;
+ }
+ if (w.colour == black)
+ return;
+ Node<T> g = w.parent;
+ if (g.right.colour == black) {
+ flipRight(g);
+ return;
+ } else {
+ pushBlack(g);
+ u.x = w.x;
+ u = w.right;
+ }
+ }
+ splice(w);
+ u.colour += w.colour;
+ u.parent = w.parent;
+ removeFixup(u);
+ return true;
+ }
+
+ void removeFixup(Node<T> u) {
+ while (u.colour > black) {
+ if (u == r) {
+ u.colour = black;
+ } else if (u.parent.left.colour == red) {
+ u = removeFixupCase1(u);
+ } else if (u == u.parent.left) {
+ u = removeFixupCase2(u);
+ } else {
+ u = removeFixupCase3(u);
+ }
+ }
+ if (u != r) {
+ Node<T> w = u.parent;
+ if (w.right.colour == red && w.left.colour == black) {
+ flipLeft(w);
+ }
+ }
+ }
+
+ Node<T> removeFixupCase3(Node<T> u) {
+ Node<T> w = u.parent;
+ Node<T> v = w.left;
+ pullBlack(w);
+ flipRight(w);
+ Node<T> q = w.left;
+ if (q.colour == red) {
+ rotateRight(w);
+ flipLeft(v);
+ pushBlack(q);
+ return q;
+ } else {
+ if (v.left.colour == red) {
+ pushBlack(v);
+ return v;
+ } else {
+ flipLeft(v);
+ return w;
+ }
+ }
+ }
+}
+```
+
+The following properties are satisfied before and after any operation:
+
+* black-height: there are the same # of black nodes on every root to the leaf path. (sum of colours on any root to leaf path is the same.)
+* no-red-edge: No two red nodes are adjacent. (except the root, `u.colour + u.parent.colour >= 1`)
+
+The root is black.
+
+
+## AVL Trees
+
+AVL trees are height-balanced.
+
+* height-balanced: at each node `u`, the height of the subtree rooted at `u.left` and the subtree rooted at `u.right` differ by at most one.
+
+AVL trees have a smaller height than red-black trees. The height
+balancing can be maintained during `add(x)` and `remove(x)` operations
+by walking back up the path to the root and performing a rebalancing
+operation at each node `u` where the height of `u`'s left and right subtrees differ by two.
+
+AVL is a self balancing binary search tree in which each node maintains
+extra information called a balance factor whose value is either -1, 0, or +1.
+
+The balance factor is determined by calculating the difference
+between the height of the left subtree and that of the right subtree of that node.
+
+Balance Factor = (Height of left subtree - height of right subtree) or (height of right subtree - height of left subtree).
+
+The self balancing property of an avl tree is maintained by the balance factory.
+
+E.g.
+
+```plaintext
+ (33) 1
+ / \
+ (9) -1 (53) -1
+ / \ \
+(8) 0 (21) 1 (61) 0
+ /
+ (11) 0
+```
+
+### Operations
+
+* Left Rotate: nodes on the right is transformed into arrangement on the left.
+* Right Rotate: nodes on the left are transformed into arrangment on the right.
+* Left-Right and Right-Left Rotate: shift left then right.
+
+
+Left Rotate:
+
+```plaintext
+1.
+ (x)
+ \
+ (y)
+
+2.
+
+ (y)
+ /
+(x)
+
+```
+
+Right Rotate:
+
+```plaintext
+1.
+ (y)
+ /
+(x)
+
+2.
+(x)
+ \
+ (y)
+```
+
+Left-Right Rotate:
+
+```plaintext
+1.
+ (z)
+ /
+(x)
+ \
+ (y)
+
+2.
+ (z)
+ /
+ (y)
+ /
+(x)
+
+3.
+ (y)
+ / \
+(x) (z)
+```
+
+
+```plaintext
+1.
+
+(z)
+ \
+ (x)
+ /
+(y)
+
+2.
+
+(z)
+ \
+ (y)
+ \
+ (x)
+
+3.
+ (y)
+ / \
+(z) (x)
+```
doc/unit/10/README.md
@@ -0,0 +1,103 @@
+# Heaps
+
+> a disorganized pile
+
+## BinaryHeap: An implicit Binary Tree
+
+Eytzinger's method can represent a complete binary tree as an array
+by laying out the nodes of the tree in a breadth-first order.
+
+* The root is stored at position 0
+* The root's left child is stored at position 1
+* The root's right child is stored at position 2.
+
+The left child of the node at index `i` is at index `left(i) = 2i + 1`
+and the right child of the node at index `i` is at index `right(i) = 2i +2`.
+The parent of the node at index `i` is at index `parent(i) = (i-1)/2`.
+
+```plaintext
+
+ -------(0)--------
+ / \
+ (1) (2)
+ / \ / \
+ (3) (4) (5) (6)
+ / \ / \ / \ / \
+(7) (8) (9) (10) (11) (12) (13) (14)
+
+| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|
+```
+
+* left: `2i+1`
+* right: `2i+2`
+
+The binary heap implements the priority queue interface.
+Ignoring the cost of `resize()` it supports the operations
+`add(x)` and `remove(x)` in `O(logn)` time per operation.
+
+```java
+class BinaryHeap {
+ T[] a;
+ int n;
+
+ int left(int i) {
+ return 2*i + 1;
+ }
+ int right(int i) {
+ return 2*i + 2;
+ }
+ int parent(int i) {
+ return (i-1)/2;
+ }
+ boolean add(T x) {
+ if (n+1 > a.length) resize();
+ a[n++] = x;
+ bubbleUp(n-1);
+ return true;
+ }
+ void bubbleUp(int i) {
+ int p = parent(i);
+ while (i > 0 && compare(a[i], a[p]) < 0) {
+ swap(i, p);
+ i = p;
+ p = parent(i);
+ }
+ }
+ T remove() {
+ T x = a[0];
+ a[0] = a[--n];
+ trickleDown(0);
+ if (3*n < a.length) resize();
+ return x;
+ }
+ void trickleDown(int i) {
+ do {
+ int j = -1;
+ int r = right(i);
+ if (r < n && compare(a[r], a[i]) < 0) {
+ int l = left(i);
+ if (compare(a[1], a[r]) < 0) {
+ j = 1;
+ } else {
+ j = r;
+ }
+ } else {
+ int l = left(i);
+ if (l < n && compare(a[l], a[i]) < 0) {
+ j = 1;
+ }
+ }
+ if (j >= 0) swap(i, j);
+ i = j;
+ } while (i >= 0);
+ }
+}
+```
+
+A `BinaryHeap` uses this technique to implicitly represent a complete
+binary tree in which the elements are `heap-ordered.`
+
+heap-ordered: The value stored at any index `i` is not smaller than the value stored at index `parent(i)`, with the exception of the root value, `i = 0`.
+The smallest value in the priority Queue is at position 0.
+
+## MeldableHeap: A randomized meldable heap
doc/unit/11/README.md
@@ -0,0 +1,134 @@
+# Comparison-Based Sorting
+
+* merge sort O(nlogn)
+* quick sort O(nlogn)
+* heap sort O(nlogn)
+
+`compare(a,b)`
+
+* -1: a < b
+* 0: a == b
+* +1: a > b
+
+## Merge-Sort
+
+is a classic recursive divide and conquer.
+
+* if `a` is at most 1 then `a` is sorted.
+* else we split `a` into two halves
+ * `a0 = a[0...(n/2)-1]`
+ * `a1 = a[(n/2)...n-1]`
+ * merge a0, a1
+
+```java
+void mergeSort(T[] a, Comparator<T> c) {
+ if (a.length <= 1) return;
+
+ T[] a0 = Arrays.copyOfRange(a, 0, a.length/2);
+ T[] a1 = Arrays.copyOfRange(a, a.length/2, a.length);
+ mergeSort(a0, c);
+ mergeSort(a1, c);
+ merge(a0, a1, a, c);
+}
+```
+
+## Quicksort
+
+Unlike mergesort which does merging after solving the two subproblems,
+quicksort does all of its work upfront.
+
+1. pick a random `pivot` element `x` from `a`
+2. partition `a` into the set of elements less than `x`, the set of elements equal to `x` and the set of elements greater than `x`.
+3. recursively sort the first and third sets in this partition.
+
+```java
+void quickSort(T[] a, Comparator<T> c) {
+ quickSort(a, 0, a.length, c);
+}
+void quickSort(T[] a, int i, int n, Comparator<T> c) {
+ if (n <= 1) return;
+ T x = a[i + rand.nextInt(n)];
+ int p = i - 1, j = i, q = i+n;
+
+ while (j < q) {
+ int comp = compare(a[j], x);
+ if (comp < 0) {
+ swap(a, j++, ++p);
+ } else if (comp > 0) {
+ swap(a, j, --q);
+ } else {
+ j++;
+ }
+ }
+ quickSort(a, i, p-i+1, c);
+ quickSort(a, q, n-(q-i), c);
+}
+```
+
+## Heap-sort
+
+In-place sorting algorithm. Uses binary heaps.
+Binary heap data structure represents a heap in a single array.
+The heap sort converts the input array into a heap and then extracts the min
+value.
+
+## Counting sort and Radix sort
+
+These are not comparison based sorting algorithms.
+These are specialized for sorting small integers.
+
+### Counting Sort
+
+This algorithm sorts using an auxiliary array of counters.
+This is very efficient for sorting an array of integers when the length,
+`n`, of the array is not much smaller than the maximum value, `k-1`,
+that appears in the array.
+
+```java
+int[] counting_sort(int[] a, int k) {
+ int c[] == new int[k];
+ for (int i = 0; i < a.length; i++)
+ c[a[i]]++;
+ for (int i = 1; i < k; i++)
+ c[i] += c[i-1];
+ int b[] new int[a.length];
+ for (int i = a.length - 1; i >= 0; i--)
+ b[--c[a[i]]] = a[i];
+ return b;
+}
+```
+
+### Radix Sort
+
+Uses several passes of counting-sort to allow for a much
+greater range of maximum values.
+
+Sorts `w-bit` integers by using `w/d` passes of counting-sort
+to sort these integers `d` bits at a time.
+
+i.e.
+
+first sorts the ints by their least significant `d` bits,
+then their next significant `d` bits, and so on until,
+in the last pass, the ints are sorted by their most
+significant `d` bits.
+
+
+```java
+int[] radixSort(int[] a) {
+ int[] b = null;
+
+ for (int p = 0; p < w/d; p++) {
+ int c[] = new int[1<<d];
+ b = new int[a.length];
+ for (int i = 0; i < a.length; i++)
+ c[(a[i] >> d*p)&((1<<d)-1)]++;
+ for (int i = 1; i < 1<<d; i++)
+ c[i] += c[i-1];
+ for (int i = a.length - 1; i >= 0; i--)
+ b[--c[(a[i] >> d*p)&((1<<d)-1)]] = a[i];
+ a = b;
+ }
+ return b;
+}
+```
doc/unit/12/README.md
@@ -0,0 +1,225 @@
+# Graphs
+
+## Directed graph
+
+```plaintext
+G = (V,E) where
+* V is a set of vertices
+* E is a set of ordered pairs of vertices called edges
+```
+
+An edge `(i, j)` is directed from `i` to `j`;
+
+* `i` is the source
+* `j` is the target
+
+A `path` in `G` is a sequence of vertices.
+
+Typical operations:
+
+* `addEdge(i,j)`: Add the edge (i, j) to E. `O(1)` time.
+* `removeEdge(i,j)`: Remove the edge `(i, j)` from E. `O(1)` time.
+* `hasEdge(i, j)`: Check if the edge `(i, j)` is an element of E. `O(1)` time.
+* `outEdges(i)`: Return a `List` of all ints `j` such that `(i,j)` is an element of E. `O(n)` time.
+* `inEdges(i)`: Return a `List` of all ints `j` such that `(j,i)` is an element of E. `O(n)` time.
+
+`O(n^2)` space.
+
+### AdjacencyMatrix: Representing a Graph by a Matrix
+
+Is a way of representing an `n` vertex graph `G = (V,E)`
+by an `n x m` matrix, `a`, whose entries are boolean values.
+
+```java
+int n;
+boolean[][] a;
+
+AdjacencyMatrix(int nO) {
+ n = nO;
+ a = new boolean[n][n];
+}
+```
+
+The matrix entry `a[i][j]` is defined as:
+
+```plaintext
+a[i][j] = { true if (i, j) element of E otherwise false
+```
+
+```java
+void addEdge(int i, int j) {
+ a[i][j] = true;
+}
+
+void removeEdge(int i, int j) {
+ a[i][j] = false;
+}
+
+boolean hasEdge(int i, int j) {
+ return a[i][j];
+}
+
+List<Integer> outEdges(int i) {
+ List<Integer> edges = new ArrayList<Integer>();
+ for (int j = 0; j < n; j++)
+ if (a[i][j])
+ edges.add(j);
+ return edges;
+}
+
+List<Integer> inEdges(int i) {
+ List<Integer> edges = new ArrayList<Integer>();
+ for (int j = 0; j < n; j++)
+ if (a[j][i])
+ edges.add(j);
+ return edges;
+}
+```
+
+It is large. It stores `n x n` boolean matrix, so it requires
+at least `n^2` bits of memory.
+
+### AdjacencyLists: A Graph as a Collection of Lists
+
+representations of graphs take a more vertex-centric approach.
+There are many possible implementations of adjacency lists.
+
+Operations:
+
+* `addEdge(i, j)`: `O(1)` time
+* `removeEdge(i, j)`: `O(deg(1))` time
+* `hasEdge(i, j)`: `O(deg(1))` time
+* `outEdges(i)`: in `O(1)` time
+* `inEdges(i)`: in `O(n + m)` time
+
+`O(n + m)` space.
+
+
+```java
+int n;
+List<Integer>[] adj;
+
+AdjacencyLists(int nO) {
+ n = nO;
+ adj = (List<Integer>[])new List[n];
+ for (int i = 0; i < n; i++)
+ adj[i] = new ArrayStack<Integer>();
+}
+
+void addEdge(int i, int j) {
+ adj[i].add(j);
+}
+
+void removeEdge(int i, int j) {
+ Iterator<Integer> it = adj[i].iterator();
+ while (it.hasNext()) {
+ if (it.next() == j) {
+ it.remove();
+ return;
+ }
+ }
+}
+
+boolean hasEdge(int i, int j) {
+ return adj[i].contains(j);
+}
+
+List<Integer> outEdges(int i) {
+ return adj[i];
+}
+
+List<Integer> inEdges(int i) {
+ List<Integer> edges = new ArrayStack<Integer>();
+ for (int j = 0; j < n; j++)
+ if (adj[j].contains(i))
+ edges.add(j);
+ return edges;
+}
+```
+
+## Graph Traversal
+
+### Breadth-First Search
+
+starts at a vertex `i` and visits, first the neighbours of `i`,
+then the neighbours of the neighbours of `i`, then the
+neighbours of the neighbours of the neighbours of `i`, and so on.
+
+It uses a `queue` and makes sure that the same vertex is
+not added more than once. It does this be keep track of each
+vertex that has been visited.
+
+```java
+void bfs(Graph g, int r) {
+ boolean[] seen = new boolean[g.nVertices()];
+ Queue<Integer> q = new SLList<Integer>();
+ q.add(r);
+ seen[r] = true;
+ while (!q.isEmpty()) {
+ int i = q.remove();
+ for (Integer j : g.outEdges(i)) {
+ if (!seen[j]) {
+ q.add(j);
+ seen[j] = true;
+ }
+ }
+ }
+}
+```
+
+time complexity: when using an adjacency list `O(n+m)`.
+
+BFS is useful for computing shortest paths.
+
+### Depth-First Search
+
+is similar to the standard algorithm for traversing binary trees.
+It fully explores one subtree before returning to the current
+node and then exploring the other subtree. Another way to
+think of depth-first search is by saying that it is similar
+to breadth-first search except that it uses a stack instead
+of a queue.
+
+Each node has a state:
+
+* not visited
+* visited
+* visiting
+
+Think of it as a recursive algorithm.
+
+```java
+void dfs(Graph g, int r) {
+ byte[] c = new byte[g.nVertices()];
+ dfs(g, r, c);
+}
+
+// uses recursive stack
+void dfs(Graph g, int i, byte[] c) {
+ c[i] = grey;
+ for (Integer j : g.outEdges(i)) {
+ if (c[j] == white) {
+ c[j] = grey;
+ dfs(g, j, c);
+ }
+ }
+ c[i] = black;
+}
+
+void dfs2(Graph g, int r) {
+ byte[] c = new byte[g.nVertices()];
+ Stack<Integer> s = new Stack<Integer>();
+ s.push(r);
+
+ while (!s.isEmpty()) {
+ int i = s.pop();
+ if (c[i] == white) {
+ c[i] = grey;
+ for (int j : g.outEdges(i))
+ s.push(j);
+ }
+ }
+}
+```
+
+time complexity: when using an adjacency list `O(n+m)` time.
doc/unit/13/README.md
@@ -0,0 +1,44 @@
+# Data Structures for Integers
+
+## BinaryTrie: A digital search tree
+
+encodes a set of `w` bit integers in a binary tree.
+
+* all leaves have depth `w`.
+* each integer is encoded as a root-to-leap path.
+
+The path for the int `x` trusn left at level `i` if the `ith`
+msb of `x` is a `0` and turns right if it is a `1`.
+
+* 3 -> 0011
+* 9 -> 1001
+* 12 -> 1100
+* 13 -> 1101
+
+
+```plaintext
+ (****)
+ / \
+ (0***) (1***)
+ / / \
+(00**) (10**) (11**)
+ \ / /
+ (001*) (100*) (110*)
+ \ \ / \
+ (3:0011) (9:1001) (12:1100) (13:1101)
+```
+
+```java
+T find(T x) {
+ int i, c = 0, ix = it.intValue(x);
+ Node u = r;
+ for (i = 0; i < w; i++) {
+ c = (ix >>> w-i-1) & 1;
+ if (u.child[c] == null) break;
+ u = u.child[c];
+ }
+ if (i == w) return u.x;
+ u = (c == 0) ? u.jump : u.jump.child[next];
+ return u == dummy ? null : u.x;
+}
+```
src/03/avl_tree.c
@@ -0,0 +1,334 @@
+#include "avl_tree.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Print a visual representation of an AVL Tree.
+ *
+ * @param tree The subtree to print
+ * @param level The level in the tree that this subtree is in
+ */
+static void print_tree(AVLTree *tree, int level) {
+ for (int i = 0; i < level; i++)
+ printf(" ");
+
+ if (tree) {
+ printf("(%d:%d)\n", tree->value, tree->height);
+
+ if (!tree->left && !tree->right)
+ return;
+ print_tree(tree->left, level + 1);
+ print_tree(tree->right, level + 1);
+ } else {
+ printf("( )\n");
+ }
+}
+
+/*
+ * Determines if a integer value is evenly divisibly by 2.
+ *
+ * @param value The integer to check
+ * @return true when the value is even otherwise false
+ */
+static bool is_even(int value) { return value % 2 == 0; }
+
+/*
+ * Determines if a integer value is an odd number
+ *
+ * @param value The integer to check
+ * @return true when the value is odd otherwise false
+ */
+static bool is_odd(int value) { return !is_even(value); }
+
+/**
+ * Converts an AVL tree to a Red Black tree with all
+ * nodes in the tree coloured black.
+ *
+ * @param tree The AVL subtree to convert
+ * @param parent The parent node of the current subtree. Use NULL for the root.
+ * @return The converted Red Black tree
+ */
+static RBTree *to_rb_tree(AVLTree *tree, AVLTree *parent) {
+ if (!tree)
+ return NULL;
+
+ RBTree *rb_tree = rb_tree_initialize(tree->value);
+
+ rb_tree->left = to_rb_tree(tree->left, tree);
+ if (rb_tree->left)
+ rb_tree->left->parent = rb_tree;
+
+ rb_tree->right = to_rb_tree(tree->right, tree);
+ if (rb_tree->right)
+ rb_tree->right->parent = rb_tree;
+ return rb_tree;
+}
+
+/**
+ * Applies the correct colouring to each descendant node in a Red Black tree.
+ *
+ * @param tree The Red Black subtree to colour
+ * @param colour The colour to apply to the provided subtree node.
+ */
+static void change_colour(RBTree *tree, enum Colour colour) {
+ if (!tree)
+ return;
+
+ int l = rb_tree_height(tree->left);
+ int r = rb_tree_height(tree->right);
+
+ tree->colour = colour;
+ change_colour(tree->left, l < r || is_odd(l) ? black : red);
+ change_colour(tree->right, r < l || is_odd(r) ? black : red);
+}
+
+/**
+ * Returns the larger integer between the two provided as arguments.
+ *
+ * @param a An integer value to compare
+ * @param b Another integer value to compare
+ * @return Returns the larger value
+ */
+static int max(int a, int b) { return (a > b) ? a : b; }
+
+/**
+ * Returns the height of an AVL subtree.
+ *
+ * @param tree The subtree to interrogate.
+ * @return The height of the subtree
+ */
+static int height_of(AVLTree *tree) { return tree == NULL ? 0 : tree->height; }
+
+/**
+ * Returns the smallest value stored in the AVL tree.
+ *
+ * @param tree The subtree to traverse to find the smallest value.
+ * @return The subtree node containing the smallest value in the tree.
+ */
+static AVLTree *smallest(AVLTree *tree) {
+ AVLTree *current = tree;
+
+ while (current && current->left != NULL)
+ current = current->left;
+
+ return current;
+}
+
+/**
+ * Performs a right rotation on an AVL subtree
+ *
+ * @param y The subtree to perform the rotation on
+ * @return The new root after the rotation is performed.
+ */
+static AVLTree *rotate_right(AVLTree *y) {
+ AVLTree *x = y->left;
+ AVLTree *t = x->right;
+
+ x->right = y;
+ y->left = t;
+
+ y->height = max(height_of(y->left), height_of(y->right)) + 1;
+ x->height = max(height_of(x->left), height_of(x->right)) + 1;
+
+ return x;
+}
+
+/**
+ * Performs a left rotation on an AVL subtree
+ *
+ * @param x The subtree to perform the rotation on
+ * @return The new root after the rotation is performed.
+ */
+static AVLTree *rotate_left(AVLTree *x) {
+ AVLTree *y = x->right;
+ AVLTree *t = y->left;
+
+ y->left = x;
+ x->right = t;
+
+ x->height = max(height_of(x->left), height_of(x->right)) + 1;
+ y->height = max(height_of(y->left), height_of(y->right)) + 1;
+
+ return y;
+}
+
+/**
+ * Calculates the balance of a subtree by taking the difference
+ * of the height of the left subtree and the right subtree.
+ *
+ * @param tree The tree to investigate.
+ * @return The balace
+ */
+static int balance_of(AVLTree *tree) {
+ return (tree == NULL) ? 0 : height_of(tree->left) - height_of(tree->right);
+}
+
+/**
+ * Compares two integers and returns -1, 0, 1.
+ * If a is equal to b then 0 is returned.
+ * If a is greater than b then 1 is returned.
+ * If a is less than b then -1 is returned.
+ *
+ * @param a An integer
+ * @param b Another integer
+ * @return Returns 0, 1, or -1.
+ */
+static int compare(int a, int b) { return (a < b) ? -1 : ((a > b) ? 1 : 0); }
+
+/**
+ * Initializes an instance of an AVL tree.
+ *
+ * @param value The value to assign to the new node in the tree.
+ * @return Returns the new AVL tree node instance.
+ */
+AVLTree *avl_tree_initialize(int value) {
+ AVLTree *tree = malloc(sizeof(AVLTree));
+ tree->value = value;
+ tree->left = NULL;
+ tree->right = NULL;
+ tree->height = 1;
+ return tree;
+}
+
+/**
+ * Computes the # of nodes stored in an AVL subtree.
+ *
+ * @param tree The subtree to investigate.
+ * @return Returns the # of descendant nodes found in the subtree.
+ */
+int avl_tree_size(AVLTree *tree) {
+ int total = 0;
+ if (tree == NULL)
+ return total;
+ if (tree->left)
+ total += avl_tree_size(tree->left);
+ if (tree->right)
+ total += avl_tree_size(tree->right);
+ return total + 1;
+}
+
+/**
+ * Inserts a new value into an AVL subtree.
+ *
+ * @param tree The subtree to attempt to insert a new value into.
+ * @param value The value to insert.
+ * @return Returns the new root of the subtree.
+ */
+AVLTree *avl_tree_insert(AVLTree *tree, int value) {
+ if (tree == NULL)
+ return avl_tree_initialize(value);
+
+ switch (compare(value, tree->value)) {
+ case -1:
+ tree->left = avl_tree_insert(tree->left, value);
+ break;
+ case 1:
+ tree->right = avl_tree_insert(tree->right, value);
+ break;
+ default:
+ return tree;
+ }
+
+ tree->height = 1 + max(height_of(tree->left), height_of(tree->right));
+
+ int balance = balance_of(tree);
+ if (balance > 1 && value < tree->left->value)
+ return rotate_right(tree);
+
+ if (balance < -1 && value > tree->right->value)
+ return rotate_left(tree);
+
+ if (balance > 1 && value > tree->left->value) {
+ tree->left = rotate_left(tree->left);
+ return rotate_right(tree);
+ }
+
+ if (balance < -1 && value < tree->right->value) {
+ tree->right = rotate_right(tree->right);
+ return rotate_left(tree);
+ }
+
+ return tree;
+}
+
+/**
+ * Deletes a value from an AVL subtree.
+ *
+ * @param tree The subtree to search to find the value to delete.
+ * @param value The value to search for.
+ * @return Returns the new root of the subtree.
+ */
+AVLTree *avl_tree_delete(AVLTree *tree, int value) {
+ if (tree == NULL)
+ return tree;
+
+ switch (compare(value, tree->value)) {
+ case -1:
+ tree->left = avl_tree_delete(tree->left, value);
+ break;
+ case 1:
+ tree->right = avl_tree_delete(tree->right, value);
+ break;
+ default:
+ if (tree->left && tree->right) {
+ AVLTree *min = smallest(tree->right);
+ tree->value = min->value;
+ tree->right = avl_tree_delete(tree->right, min->value);
+ } else {
+ AVLTree *tmp = tree->left ? tree->left : tree->right;
+
+ if (tmp) {
+ *tree = *tmp;
+ free(tmp);
+ } else {
+ free(tree);
+ return NULL;
+ }
+ }
+ break;
+ }
+
+ tree->height = 1 + max(height_of(tree->left), height_of(tree->right));
+
+ int balance = balance_of(tree);
+ if (balance > 1 && balance_of(tree->left) >= 0)
+ return rotate_right(tree);
+
+ if (balance > 1 && balance_of(tree->left) < 0) {
+ tree->left = rotate_left(tree->left);
+ return rotate_right(tree);
+ }
+
+ if (balance < -1 && balance_of(tree->right) <= 0)
+ return rotate_left(tree);
+
+ if (balance < -1 && balance_of(tree->right) > 0) {
+ tree->right = rotate_right(tree->right);
+ return rotate_left(tree);
+ }
+
+ return tree;
+}
+
+/**
+ * Converts an AVL tree to a Red Black tree.
+ *
+ * @param tree The AVL tree to convert.
+ * @return Returns a new Red Black tree.
+ */
+RBTree *avl_tree_to_rb_tree(AVLTree *tree) {
+ if (!tree)
+ return NULL;
+
+ RBTree *rb_tree = to_rb_tree(tree, NULL);
+ change_colour(rb_tree, black);
+ return rb_tree;
+}
+
+/**
+ * Prints a visual inspection of
+ * an AVL tree for debugging purposes to stdout.
+ *
+ * @param tree The tree to visualize
+ */
+void avl_tree_inspect(AVLTree *tree) { print_tree(tree, 0); }
src/03/avl_tree.h
@@ -0,0 +1,15 @@
+#include "rb_tree.h"
+
+typedef struct node {
+ struct node *left;
+ struct node *right;
+ int height;
+ int value;
+} AVLTree;
+
+AVLTree *avl_tree_initialize(int value);
+int avl_tree_size(AVLTree *tree);
+AVLTree *avl_tree_insert(AVLTree *tree, int value);
+AVLTree *avl_tree_delete(AVLTree *tree, int value);
+void avl_tree_inspect(AVLTree *tree);
+RBTree *avl_tree_to_rb_tree(AVLTree *tree);
src/03/avl_tree_test.c
@@ -0,0 +1,400 @@
+#include "avl_tree.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Ensure(initialize_returns_new_tree) {
+ AVLTree *tree = avl_tree_initialize(1);
+ assert_that(tree, is_not_equal_to(NULL));
+}
+
+Ensure(size_returns_zero) {
+ AVLTree *tree = avl_tree_initialize(1);
+
+ assert_that(avl_tree_size(tree), is_equal_to(1));
+}
+
+Ensure(insert_changes_size) {
+ AVLTree *tree = avl_tree_initialize(5);
+ avl_tree_insert(tree, 4);
+
+ assert_that(avl_tree_size(tree), is_equal_to(2));
+}
+
+Ensure(insert_changes_height) {
+ AVLTree *tree = avl_tree_initialize(5);
+ tree = avl_tree_insert(tree, 4);
+
+ assert_that(tree->height, is_equal_to(2));
+ assert_that(tree->left->height, is_equal_to(1));
+}
+
+Ensure(insert_creates_a_new_root) {
+ AVLTree *tree = avl_tree_insert(NULL, 10);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(10));
+ assert_that(tree->left, is_equal_to(NULL));
+ assert_that(tree->right, is_equal_to(NULL));
+}
+
+Ensure(insert_performs_a_left_rotation) {
+ /*
+ (10) (20)
+ \ / \
+ (20) -> (10) (30)
+ \
+ (30)
+ */
+ AVLTree *tree = avl_tree_initialize(10);
+ tree = avl_tree_insert(tree, 20);
+ tree = avl_tree_insert(tree, 30);
+
+ assert_that(tree->value, is_equal_to(20));
+ assert_that(tree->left->value, is_equal_to(10));
+ assert_that(tree->right->value, is_equal_to(30));
+};
+
+Ensure(insert_performs_a_right_rotation) {
+ /*
+ (30) (20)
+ / / \
+ (20) --> (10) (30)
+ /
+ (10)
+ */
+ AVLTree *tree = avl_tree_initialize(30);
+ tree = avl_tree_insert(tree, 20);
+ tree = avl_tree_insert(tree, 10);
+
+ assert_that(tree->value, is_equal_to(20));
+ assert_that(tree->left->value, is_equal_to(10));
+ assert_that(tree->right->value, is_equal_to(30));
+}
+
+Ensure(insert_performs_a_left_right_rotation) {
+ /*
+ (30) (20)
+ / / \
+ (10) -> (10) (30)
+ \
+ (20)
+ */
+ AVLTree *tree = avl_tree_initialize(30);
+ tree = avl_tree_insert(tree, 10);
+ tree = avl_tree_insert(tree, 20);
+
+ assert_that(tree->value, is_equal_to(20));
+ assert_that(tree->left->value, is_equal_to(10));
+ assert_that(tree->right->value, is_equal_to(30));
+}
+
+Ensure(insert_performs_a_right_left_rotation) {
+ /*
+ (10) (20)
+ \ / \
+ (30) --> (10) (30)
+ /
+ (20)
+ */
+ AVLTree *tree = avl_tree_initialize(10);
+ tree = avl_tree_insert(tree, 30);
+ tree = avl_tree_insert(tree, 20);
+
+ assert_that(tree->value, is_equal_to(20));
+ assert_that(tree->left->value, is_equal_to(10));
+ assert_that(tree->right->value, is_equal_to(30));
+}
+
+Ensure(delete_handles_left_left_case) {
+ /*
+ (z) (y)
+ / \ / \
+ (y) (T4) (X) (z)
+ / \ --> / \ / \
+ (x) (T3) (T1) (T2) (T3) (T4)
+ / \
+ (T1) (T2)
+
+ Delete (37):
+
+ (30) (20)
+ / \ / \
+ (20) (35) (10) (30)
+ / \ \ --> / \ / \
+ (10) (25) *(37) (5) (15) (25) (35)
+ / \
+ (5) (15)
+ */
+
+ AVLTree *tree = avl_tree_initialize(30);
+ tree = avl_tree_insert(tree, 35);
+ tree = avl_tree_insert(tree, 20);
+ tree = avl_tree_insert(tree, 10);
+ tree = avl_tree_insert(tree, 25);
+ tree = avl_tree_insert(tree, 37);
+ tree = avl_tree_insert(tree, 15);
+ tree = avl_tree_insert(tree, 5);
+
+ tree = avl_tree_delete(tree, 37);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(20));
+ assert_that(tree->left->value, is_equal_to(10));
+ assert_that(tree->left->left->value, is_equal_to(5));
+ assert_that(tree->left->right->value, is_equal_to(15));
+
+ assert_that(tree->right->value, is_equal_to(30));
+ assert_that(tree->right->left->value, is_equal_to(25));
+ assert_that(tree->right->right->value, is_equal_to(35));
+}
+
+Ensure(delete_handles_left_right_case) {
+ /*
+ (z) (x)
+ / \ / \
+ (y) (T4) (y) (z)
+ / \ --> / \ / \
+ (T1) (x) (T1) (T2) (T3) (T4)
+ / \
+ (T2) (T3)
+
+ Delete (37):
+
+ (30) (25)
+ / \ / \
+ (20) (35) (20) (30)
+ / \ \ --> / \ / \
+ (10) (25) *(37) (10) (22) (27) (35)
+ / \
+ (22) (27)
+ */
+ AVLTree *tree = avl_tree_initialize(30);
+ tree = avl_tree_insert(tree, 20);
+ tree = avl_tree_insert(tree, 35);
+ tree = avl_tree_insert(tree, 10);
+ tree = avl_tree_insert(tree, 37);
+ tree = avl_tree_insert(tree, 25);
+ tree = avl_tree_insert(tree, 22);
+ tree = avl_tree_insert(tree, 27);
+
+ tree = avl_tree_delete(tree, 37);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(25));
+ assert_that(tree->left->value, is_equal_to(20));
+ assert_that(tree->left->left->value, is_equal_to(10));
+ assert_that(tree->left->right->value, is_equal_to(22));
+
+ assert_that(tree->right->value, is_equal_to(30));
+ assert_that(tree->right->left->value, is_equal_to(27));
+ assert_that(tree->right->right->value, is_equal_to(35));
+}
+
+Ensure(delete_handles_right_right_case) {
+ /*
+ (z) (y)
+ / \ / \
+ (T4) (y) (z) (x)
+ / \ --> / \ / \
+ (T3) (x) (T4) (T3) (T2) (T1)
+ / \
+ (T2) (T1)
+
+
+ (20) (30)
+ / \ / \
+ (15) (30) (20) (35)
+ / / \ --> / \ / \
+ *(10) (25) (35) (15) (25) (33) (37)
+ / \
+ (33) (37)
+ */
+ AVLTree *tree = avl_tree_initialize(20);
+
+ tree = avl_tree_insert(tree, 30);
+ tree = avl_tree_insert(tree, 15);
+ tree = avl_tree_insert(tree, 10);
+ tree = avl_tree_insert(tree, 20);
+ tree = avl_tree_insert(tree, 25);
+ tree = avl_tree_insert(tree, 35);
+ tree = avl_tree_insert(tree, 33);
+ tree = avl_tree_insert(tree, 37);
+
+ tree = avl_tree_delete(tree, 10);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(30));
+
+ assert_that(tree->left->value, is_equal_to(20));
+ assert_that(tree->left->left->value, is_equal_to(15));
+ assert_that(tree->left->right->value, is_equal_to(25));
+
+ assert_that(tree->right->value, is_equal_to(35));
+ assert_that(tree->right->left->value, is_equal_to(33));
+ assert_that(tree->right->right->value, is_equal_to(37));
+}
+
+Ensure(delete_handles_right_left) {
+ /*
+ (z) (x)
+ / \ / \
+ (T4) (y) (z) (y)
+ / \ / \ / \
+ (x) (T1) --> (T4) (T3) (T2) (T1)
+ / \
+ (T3) (T2)
+
+
+ (20) (22)
+ / \ / \
+ (15) (25) (20) (25)
+ / / \ / \ / \
+ *(10) (22) (30) --> (15) (21) (23) (30)
+ / \
+ (21) (23)
+ */
+
+ AVLTree *tree = avl_tree_initialize(20);
+ tree = avl_tree_insert(tree, 15);
+ tree = avl_tree_insert(tree, 25);
+ tree = avl_tree_insert(tree, 10);
+ tree = avl_tree_insert(tree, 22);
+ tree = avl_tree_insert(tree, 30);
+ tree = avl_tree_insert(tree, 21);
+ tree = avl_tree_insert(tree, 23);
+
+ tree = avl_tree_delete(tree, 10);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(22));
+ assert_that(tree->left->value, is_equal_to(20));
+ assert_that(tree->left->left->value, is_equal_to(15));
+ assert_that(tree->left->right->value, is_equal_to(21));
+
+ assert_that(tree->right->value, is_equal_to(25));
+ assert_that(tree->right->left->value, is_equal_to(23));
+ assert_that(tree->right->right->value, is_equal_to(30));
+}
+
+Ensure(delete_handles_a_complicated_and_large_tree) {
+ int items[] = {44, 17, 62, 10, 32, 50, 78, 21, 48,
+ 54, 72, 88, 45, 49, 52, 56, 81, 92};
+ unsigned int length = sizeof(items) / sizeof(items[0]);
+ AVLTree *tree = NULL;
+
+ for (int i = 0; i < length; i++)
+ tree = avl_tree_insert(tree, items[i]);
+
+ tree = avl_tree_delete(tree, 32);
+
+ assert_that(tree->value, is_equal_to(62));
+}
+
+Ensure(delete_handles_a_complicated_and_small_tree) {
+ int items[] = {9, 1, 10, 0, 5, 11, -1, 2, 6};
+ unsigned int length = sizeof(items) / sizeof(items[0]);
+ AVLTree *tree = NULL;
+
+ for (int i = 0; i < length; i++)
+ tree = avl_tree_insert(tree, items[i]);
+
+ tree = avl_tree_delete(tree, 10);
+
+ assert_that(tree->value, is_equal_to(1));
+}
+
+Ensure(delete_returns_a_null_root) {
+ AVLTree *tree = avl_tree_delete(NULL, 10);
+
+ assert_that(tree, is_equal_to(NULL));
+}
+
+Ensure(to_rb_tree_returns_a_new_red_black_tree) {
+ /*
+ (20:3) (20:b)
+ / \ --> / \
+ (15:2) (30:2) (15:b) (30:b)
+ / \ \ / \ \
+ (10:1) (17:1) (35:1) (10:r) (17:r) (35:r)
+ */
+ AVLTree *tree = NULL;
+ RBTree *expected = NULL;
+ int items[] = {20, 15, 30, 10, 17, 35};
+ int length = sizeof(items) / sizeof(items[0]);
+
+ for (int i = 0; i < length; i++) {
+ tree = avl_tree_insert(tree, items[i]);
+ expected = rb_tree_insert(expected, items[i]);
+ }
+
+ RBTree *actual = avl_tree_to_rb_tree(tree);
+
+ assert_that(rb_equals(expected, actual), is_equal_to(true));
+ assert_that(rb_tree_is_valid(actual), is_equal_to(true));
+ assert_that(rb_tree_is_valid(expected), is_equal_to(true));
+}
+
+Ensure(to_rb_tree_handles_trees_with_a_large_depth) {
+ AVLTree *subject = NULL;
+ int n = 100;
+
+ for (int i = 0; i < n; i++)
+ subject = avl_tree_insert(subject, i);
+
+ RBTree *actual = avl_tree_to_rb_tree(subject);
+
+ assert_that(rb_tree_is_valid(actual), is_equal_to(true));
+
+ for (int i = 0; i < n; i++) {
+ RBTree *node = rb_tree_find(actual, i);
+
+ assert_that(node, is_not_equal_to(NULL));
+ assert_that(node->value, is_equal_to(i));
+ }
+}
+
+TestSuite *avl_tree_tests() {
+ TestSuite *x = create_test_suite();
+ add_test(x, initialize_returns_new_tree);
+
+ add_test(x, size_returns_zero);
+
+ add_test(x, insert_changes_size);
+ add_test(x, insert_changes_height);
+ add_test(x, insert_creates_a_new_root);
+ add_test(x, insert_performs_a_left_rotation);
+ add_test(x, insert_performs_a_right_rotation);
+ add_test(x, insert_performs_a_left_right_rotation);
+ add_test(x, insert_performs_a_right_left_rotation);
+
+ add_test(x, delete_handles_left_left_case);
+ add_test(x, delete_handles_left_right_case);
+ add_test(x, delete_handles_right_right_case);
+ add_test(x, delete_handles_right_left);
+ add_test(x, delete_handles_a_complicated_and_large_tree);
+ add_test(x, delete_handles_a_complicated_and_small_tree);
+ add_test(x, delete_returns_a_null_root);
+
+ add_test(x, to_rb_tree_returns_a_new_red_black_tree);
+ add_test(x, to_rb_tree_handles_trees_with_a_large_depth);
+ return x;
+}
+
+TestSuite *btree_tests();
+TestSuite *graph_tests();
+TestSuite *matrix_tests();
+TestSuite *meldable_heap_tests();
+TestSuite *rb_tree_tests();
+TestSuite *sort_tests();
+
+int main(int argc, char **argv) {
+ TestSuite *suite = create_test_suite();
+ add_suite(suite, avl_tree_tests());
+ add_suite(suite, btree_tests());
+ add_suite(suite, graph_tests());
+ add_suite(suite, matrix_tests());
+ add_suite(suite, meldable_heap_tests());
+ add_suite(suite, rb_tree_tests());
+ add_suite(suite, sort_tests());
+ return run_test_suite(suite, create_text_reporter());
+}
src/03/btree.c
@@ -0,0 +1,108 @@
+#include "btree.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Print a visual representation of an binary tree.
+ *
+ * @param tree The subtree to print
+ * @param level The level in the tree that this subtree is in
+ */
+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 instance of an binary tree.
+ *
+ * @param data The value to assign to the new node in the tree.
+ * @return Returns the new binary tree node instance.
+ */
+BTree *btree_initialize(int data) {
+ BTree *tree = malloc(sizeof(BTree));
+ tree->left = NULL;
+ tree->right = NULL;
+ tree->data = data;
+ return tree;
+}
+
+/**
+ * Inserts a new value into a binary subtree.
+ *
+ * @param tree The subtree to attempt to insert a new value into.
+ * @param data The data to insert into the tree.
+ * @return Returns the new root of the subtree.
+ */
+BTree *btree_insert(BTree *tree, int data) {
+ if (!tree)
+ return btree_initialize(data);
+
+ if (data <= tree->data)
+ if (tree->left)
+ btree_insert(tree->left, data);
+ else
+ tree->left = btree_initialize(data);
+ else if (tree->right)
+ btree_insert(tree->right, data);
+ else
+ tree->right = btree_initialize(data);
+
+ return tree;
+}
+
+/**
+ * Returns the height of a binary subtree.
+ *
+ * @param tree The subtree to interrogate.
+ * @return The height of the subtree
+ */
+int btree_height(BTree *tree) {
+ if (tree == NULL)
+ return 0;
+
+ int left = btree_height(tree->left);
+ int right = btree_height(tree->right);
+
+ return (left > right) ? left + 1 : right + 1;
+}
+
+/**
+ * Prints a visual inspection of
+ * a binary tree for debugging purposes to stdout.
+ *
+ * @param tree The tree to visualize
+ */
+void btree_inspect(BTree *tree) { inspect(tree, 0); }
+
+int btree_leaves(BTree *tree) {
+ if (tree == NULL)
+ return 0;
+
+ if (tree->left == NULL && tree->right == NULL)
+ return 1;
+
+ return btree_leaves(tree->left) + btree_leaves(tree->right);
+}
+
+/**
+ * Generates a binary tree with a desired number of leaf
+ * nodes.
+ *
+ * @param leaves The total number of leaf nodes to generate in the tree.
+ * @return Returns a new binary tree.
+ */
+BTree *btree_generate(int leaves) {
+ BTree *tree = NULL;
+
+ while (btree_leaves(tree) < leaves)
+ tree = btree_insert(tree, rand());
+ return tree;
+}
src/03/btree.h
@@ -0,0 +1,11 @@
+typedef struct node {
+ struct node *left;
+ struct node *right;
+ int data;
+} BTree;
+
+BTree *btree_initialize(int data);
+BTree *btree_insert(BTree *tree, int data);
+int btree_height(BTree *tree);
+void btree_inspect(BTree *tree);
+BTree *btree_generate(int leaves);
src/03/btree_test.c
@@ -0,0 +1,37 @@
+#include "btree.h"
+#include "rb_tree.h"
+#include <cgreen/cgreen.h>
+#include <math.h>
+#include <string.h>
+
+Ensure(initialize_returns_new_btree) {
+ BTree *tree = btree_initialize(10);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->data, is_equal_to(10));
+}
+
+Ensure(height_returns_height_of_tree) {
+ BTree *tree = NULL;
+
+ int n = 10;
+ for (int i = 0; i < n; ++i)
+ tree = btree_insert(tree, i);
+
+ assert_that(btree_height(tree), is_equal_to(n));
+}
+
+Ensure(tree_with_k_leaves_has_height_of_log_k) {
+ for (int k = 0; k < 500; ++k)
+ assert_that(btree_height(btree_generate(k)) >= log2(k), is_equal_to(true));
+}
+
+TestSuite *btree_tests() {
+ TestSuite *x = create_test_suite();
+
+ add_test(x, initialize_returns_new_btree);
+ add_test(x, height_returns_height_of_tree);
+ add_test(x, tree_with_k_leaves_has_height_of_log_k);
+
+ return x;
+}
src/03/graph.c
@@ -0,0 +1,67 @@
+#include "graph.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Creates a new Vertex for use in a Graph.
+ *
+ * @param label The label to attach to the node.
+ * @return Returns a new vertex
+ */
+Vertex *vertex_initialize(char label) {
+ Vertex *item = malloc(sizeof(Vertex));
+ item->label = label;
+ return item;
+};
+
+/**
+ * Initializes a new Graph
+ *
+ * @return Returns a new instance of a Graph.
+ */
+Graph *graph_initialize(void) {
+ Graph *item = malloc(sizeof(Graph));
+ for (int i = 0; i < 128; ++i)
+ item->vertices[i] = NULL;
+ return item;
+}
+
+/**
+ * Inserts a new vertex into a graph with the provided label.
+ *
+ * @param graph The graph to insert a new vertex into
+ * @param label The label to apply to the new vertex.
+ * @return Returns the new vertex
+ */
+Vertex *graph_add_vertex(Graph *graph, char label) {
+ Vertex *item = vertex_initialize(label);
+ graph->vertices[(int)label] = item;
+ return item;
+}
+
+/**
+ * Updates a adjacency matrix to indicate that an edge exists
+ * between two vertexes.
+ *
+ * @param graph The graph to modify.
+ * @param a The vertex that points to vertex b.
+ * @param b The vertex that vertex a points to.
+ */
+void graph_add_edge(Graph *graph, Vertex *a, Vertex *b) {
+ graph->edges[a->label][b->label] = true;
+}
+
+/**
+ * Returns true or false to specify if vertex `a`
+ * in a graph is connected to vertex `b` in the same
+ * graph.
+ *
+ * @param graph The graph to investigate
+ * @param a The starting vertext to check
+ * @param b The vertex that vertex a might be pointing at.
+ * @return Returns true if an edge exists between the two vertexes otherwise
+ * false.
+ */
+bool graph_has_edge(Graph *graph, Vertex *a, Vertex *b) {
+ return graph->edges[a->label][b->label];
+}
src/03/graph.h
@@ -0,0 +1,15 @@
+#include <stdbool.h>
+
+typedef struct {
+ char label;
+} Vertex;
+
+typedef struct {
+ Vertex *vertices[128];
+ bool edges[128][128];
+} Graph;
+
+Graph *graph_initialize(void);
+Vertex *graph_add_vertex(Graph *graph, char label);
+void graph_add_edge(Graph *graph, Vertex *a, Vertex *b);
+bool graph_has_edge(Graph *graph, Vertex *a, Vertex *b);
src/03/graph_test.c
@@ -0,0 +1,74 @@
+#include "graph.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Ensure(initialize_returns_a_new_graph) {
+ Graph *graph = graph_initialize();
+
+ assert_that(graph, is_not_equal_to(NULL));
+ for (int i = 0; i < 128; ++i)
+ assert_that(graph->vertices[i], is_equal_to(NULL));
+}
+
+Ensure(add_vertex_returns_a_new_vertex) {
+ Graph *graph = graph_initialize();
+ char label = 'a';
+ Vertex *a = graph_add_vertex(graph, label);
+
+ assert_that(a, is_not_equal_to(NULL));
+ assert_that(graph->vertices[(int)label], is_equal_to(a));
+}
+
+Ensure(add_vertex_adds_max_number_of_verticies_to_graph) {
+ Graph *graph = graph_initialize();
+
+ for (int i = 0; i < 128; ++i) {
+ Vertex *item = graph_add_vertex(graph, (char)i);
+ assert_that(item, is_not_equal_to(NULL));
+ assert_that(graph->vertices[i], is_equal_to(item));
+ }
+}
+
+Ensure(add_edge_connects_two_vertices) {
+ Graph *graph = graph_initialize();
+
+ graph_add_edge(graph, graph_add_vertex(graph, 'a'),
+ graph_add_vertex(graph, 'b'));
+
+ assert_that(graph->edges['a']['b'], is_equal_to(true));
+ assert_that(graph->edges['b']['a'], is_equal_to(false));
+}
+
+Ensure(has_edge_returns_true) {
+ Graph *graph = graph_initialize();
+ Vertex *a = graph_add_vertex(graph, 'a');
+ Vertex *b = graph_add_vertex(graph, 'b');
+
+ graph_add_edge(graph, a, b);
+
+ assert_that(graph_has_edge(graph, a, b), is_equal_to(true));
+}
+
+Ensure(has_edge_returns_false) {
+ Graph *graph = graph_initialize();
+ Vertex *a = graph_add_vertex(graph, 'a');
+ Vertex *b = graph_add_vertex(graph, 'b');
+ Vertex *c = graph_add_vertex(graph, 'c');
+
+ graph_add_edge(graph, a, b);
+
+ assert_that(graph_has_edge(graph, a, c), is_equal_to(false));
+}
+
+TestSuite *graph_tests() {
+ TestSuite *x = create_test_suite();
+
+ add_test(x, add_edge_connects_two_vertices);
+ add_test(x, add_vertex_adds_max_number_of_verticies_to_graph);
+ add_test(x, add_vertex_returns_a_new_vertex);
+ add_test(x, has_edge_returns_true);
+ add_test(x, has_edge_returns_false);
+ add_test(x, initialize_returns_a_new_graph);
+
+ return x;
+}
src/03/Makefile
@@ -0,0 +1,37 @@
+#!/usr/bin/make -f
+SHELL=/bin/sh
+
+CC=clang
+TEST_LIBS = -lcgreen -lm
+
+BUILDDIR := build
+OBJS := $(addprefix $(BUILDDIR)/,avl_tree.o rb_tree.o sort.o graph.o matrix.o meldable_heap.o btree.o)
+TEST_OBJS := $(addprefix $(BUILDDIR)/,avl_tree_test.o rb_tree_test.o sort_test.o graph_test.o matrix_test.o meldable_heap_test.o btree_test.o)
+
+$(BUILDDIR)/%.o : %.c
+ $(COMPILE.c) $(OUTPUT_OPTION) $<
+
+.PHONY: all
+all: $(OBJS) $(BUILDDIR)/main.o
+ $(CC) $(OBJS) $(BUILDDIR)/main.o $(TEST_LIBS) -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/03/matrix.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+char labels[26] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
+
+/**
+ * Traverses a graph represented as an adjacency matrix
+ * to visit every vertex in the graph and traverse each
+ * edge in both directions only once.
+ *
+ * @param n The # of vertexes in the graph
+ * @param graph An adjacency matrix that represents the graph
+ * @param visited An array that keeps track of which vertexes have been visited
+ * @param vertex The current vertex to traverse.
+ */
+void matrix_traverse(int n, int graph[n][n], int visited[n], int vertex) {
+ printf("->(%c)", labels[vertex]);
+ visited[vertex] = 1;
+
+ for (int edge = 0; edge < n; ++edge) {
+ if (!visited[edge] && graph[vertex][edge] > 0) {
+ graph[vertex][edge] = 0;
+ matrix_traverse(n, graph, visited, edge);
+ graph[edge][vertex] = 0;
+ printf("->(%c)", labels[vertex]);
+ }
+ }
+ for (int edge = 0; edge < n; ++edge) {
+ if (graph[vertex][edge] > 0 && graph[edge][vertex] > 0) {
+ graph[vertex][edge] = 0;
+ matrix_traverse(n, graph, visited, edge);
+ graph[edge][vertex] = 0;
+ printf("->(%c)", labels[vertex]);
+ }
+ }
+}
+
+/**
+ * Prints a visual representation of an
+ * adjacency matrix to stdout out for debugging purposes.
+ *
+ * @param n The number of vertexes in the graph.
+ * @param graph The adjacency matrix that represents the graph.
+ */
+void matrix_inspect(int n, int graph[n][n]) {
+ printf("\n");
+
+ printf("| ");
+ for (int i = 0; i < n; ++i)
+ printf("|%c", labels[i]);
+ printf("|\n");
+
+ for (int i = 0; i < n; ++i) {
+ printf("|%c|", labels[i]);
+ for (int j = 0; j < n; ++j)
+ printf("%d|", graph[i][j]);
+ printf("\n");
+ }
+}
src/03/matrix.h
@@ -0,0 +1,3 @@
+
+void matrix_traverse(int n, int graph[n][n], int visited[n], int vertex);
+void matrix_inspect(int n, int graph[n][n]);
src/03/matrix_test.c
@@ -0,0 +1,41 @@
+#include "matrix.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Ensure(every_edge_is_traversed_in_both_directions_at_least_once) {
+ int n = 16;
+ int visited[16] = {0};
+ int graph[16][16] = {
+ {0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
+ {1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0},
+ {0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0},
+ {0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+ {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0},
+ };
+
+ matrix_traverse(n, graph, visited, 0);
+ printf("\n");
+
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ assert_that(graph[i][j], is_equal_to(0));
+}
+
+TestSuite *matrix_tests() {
+ TestSuite *x = create_test_suite();
+
+ add_test(x, every_edge_is_traversed_in_both_directions_at_least_once);
+
+ return x;
+}
src/03/meldable_heap.c
@@ -0,0 +1,122 @@
+#include "meldable_heap.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Compares two integers and returns -1, 0, 1.
+ * If a is equal to b then 0 is returned.
+ * If a is greater than b then 1 is returned.
+ * If a is less than b then -1 is returned.
+ *
+ * @param a An integer
+ * @param b Another integer
+ * @return Returns 0, 1, or -1.
+ */
+static int compare(int a, int b) { return (a < b) ? -1 : ((a > b) ? 1 : 0); }
+
+/**
+ * Print a visual representation of a heap.
+ *
+ * @param heap The subtree to print
+ * @param level The level in the heap that this subtree is in
+ */
+static void print_tree(MeldableHeap *heap, int level) {
+ for (int i = 0; i < level; i++)
+ printf(" ");
+
+ if (heap) {
+ printf("(%d)\n", heap->value);
+
+ if (!heap->left && !heap->right)
+ return;
+ print_tree(heap->left, level + 1);
+ print_tree(heap->right, level + 1);
+ } else {
+ printf("( )\n");
+ }
+}
+
+/**
+ * Initializes an instance of an meldable heap.
+ *
+ * @param value The value to assign to the new node in the heap.
+ * @return Returns the new heap node instance.
+ */
+MeldableHeap *meldable_heap_initialize(int value) {
+ MeldableHeap *heap = malloc(sizeof(MeldableHeap));
+ heap->left = NULL;
+ heap->right = NULL;
+ heap->parent = NULL;
+ heap->value = value;
+ return heap;
+};
+
+/**
+ * Adds a new value into a heap.
+ *
+ * @param heap The subtree to attempt to insert a new value into.
+ * @param value The value to insert.
+ * @return Returns the new root of the subtree.
+ */
+MeldableHeap *meldable_heap_add(MeldableHeap *heap, int value) {
+ MeldableHeap *root =
+ meldable_heap_merge(meldable_heap_initialize(value), heap);
+ root->parent = NULL;
+ return root;
+}
+
+/**
+ * Merges to meldable heaps into a single heap and returns the
+ * root of the new heap.
+ *
+ * @param h1 A heap
+ * @param h2 Another heap
+ * @return Returns the merged heap
+ */
+MeldableHeap *meldable_heap_merge(MeldableHeap *h1, MeldableHeap *h2) {
+ if (h1 == NULL)
+ return h2;
+ if (h2 == NULL)
+ return h1;
+
+ if (compare(h2->value, h1->value) < 0)
+ return meldable_heap_merge(h2, h1);
+
+ if (rand() % 2 == 0) {
+ h1->left = meldable_heap_merge(h1->left, h2);
+ h1->left->parent = h1;
+ } else {
+ h1->right = meldable_heap_merge(h1->right, h2);
+ h1->right->parent = h1;
+ }
+ return h1;
+}
+
+/**
+ * Prints a visual inspection of
+ * a heap for debugging purposes to stdout.
+ *
+ * @param heap The heap to visualize
+ */
+void meldable_heap_inspect(MeldableHeap *heap) { print_tree(heap, 0); }
+
+/**
+ * Removes a value from a meldable heap.
+ *
+ * @param heap The subtree to remove
+ */
+void meldable_heap_remove(MeldableHeap *heap) {
+ MeldableHeap *replacement = meldable_heap_merge(heap->left, heap->right);
+
+ if (replacement)
+ replacement->parent = heap->parent;
+
+ if (!heap->parent)
+ return;
+
+ if (heap->parent->left == heap)
+ heap->parent->left = replacement;
+ else
+ heap->parent->right = replacement;
+}
src/03/meldable_heap.h
@@ -0,0 +1,12 @@
+typedef struct mnode {
+ struct mnode *left;
+ struct mnode *parent;
+ struct mnode *right;
+ int value;
+} MeldableHeap;
+
+MeldableHeap *meldable_heap_initialize(int value);
+MeldableHeap *meldable_heap_add(MeldableHeap *heap, int value);
+MeldableHeap *meldable_heap_merge(MeldableHeap *heap, MeldableHeap* other);
+void meldable_heap_inspect(MeldableHeap *heap);
+void meldable_heap_remove(MeldableHeap *heap);
src/03/meldable_heap_test.c
@@ -0,0 +1,101 @@
+#include "meldable_heap.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Ensure(add_inserts_item_into_right_subtree) {
+ MeldableHeap *heap = meldable_heap_initialize(5);
+ heap = meldable_heap_add(heap, 3);
+
+ assert_that(heap->value, is_equal_to(3));
+ assert_that(heap->right->value, is_equal_to(5));
+}
+
+Ensure(add_inserts_item_into_left_subtree) {
+ MeldableHeap *heap = meldable_heap_initialize(5);
+ heap = meldable_heap_add(heap, 8);
+
+ assert_that(heap->value, is_equal_to(5));
+ assert_that(heap->right->value, is_equal_to(8));
+}
+
+/*
+ (1)
+ / \
+ (3) (2)
+ / \ / \
+ (10) (6) (7) (4)
+ / \ /
+ (9) (8)(5)
+*/
+Ensure(add_inserts_multiple_items_into_the_subtree) {
+ MeldableHeap *heap = NULL;
+
+ for (int i = 1; i <= 10; ++i)
+ heap = meldable_heap_add(heap, i);
+
+ assert_that(heap->value, is_equal_to(1));
+
+ assert_that(heap->right->value, is_equal_to(2));
+ assert_that(heap->right->right->value, is_equal_to(4));
+ assert_that(heap->right->right->left->value, is_equal_to(5));
+
+ assert_that(heap->right->left->value, is_equal_to(7));
+ assert_that(heap->right->left->left->value, is_equal_to(9));
+ assert_that(heap->right->left->right->value, is_equal_to(8));
+
+ assert_that(heap->left->value, is_equal_to(3));
+ assert_that(heap->left->left->value, is_equal_to(10));
+ assert_that(heap->left->right->value, is_equal_to(6));
+}
+
+/*
+ (1)
+ / \
+ (3) (2)
+ / \ / \
+ (10) (6) (7) (4)
+ / \ /
+ (9) (8)(5)
+
+ to
+
+ (1)
+ / \
+ (3) (2)
+ / \ / \
+ (10) (6) (4)
+ / \ /
+ (9) (8)(5)
+*/
+Ensure(remove_removes_the_node_from_the_tree) {
+ MeldableHeap *heap = NULL;
+
+ for (int i = 1; i <= 10; ++i)
+ heap = meldable_heap_add(heap, i);
+
+ meldable_heap_remove(heap->right->left);
+
+ assert_that(heap->value, is_equal_to(1));
+
+ assert_that(heap->right->value, is_equal_to(2));
+ assert_that(heap->right->right->value, is_equal_to(4));
+ assert_that(heap->right->right->left->value, is_equal_to(5));
+
+ assert_that(heap->right->left->value, is_equal_to(8));
+ assert_that(heap->right->left->left->value, is_equal_to(9));
+ assert_that(heap->right->left->right, is_equal_to(NULL));
+
+ assert_that(heap->left->value, is_equal_to(3));
+ assert_that(heap->left->left->value, is_equal_to(10));
+ assert_that(heap->left->right->value, is_equal_to(6));
+}
+
+TestSuite *meldable_heap_tests() {
+ TestSuite *x = create_test_suite();
+
+ add_test(x, add_inserts_item_into_right_subtree);
+ add_test(x, add_inserts_item_into_left_subtree);
+ add_test(x, add_inserts_multiple_items_into_the_subtree);
+ add_test(x, remove_removes_the_node_from_the_tree);
+ return x;
+}
src/03/rb_tree.c
@@ -0,0 +1,399 @@
+#include "rb_tree.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ * Implementation derived from:
+ * * https://en.wikipedia.org/wiki/Red%E2%80%93black_tree#Insertion
+ */
+
+/**
+ * Returns the larger integer between the two provided as arguments.
+ *
+ * @param a An integer value to compare
+ * @param b Another integer value to compare
+ * @return Returns the larger value
+ */
+static int max(int a, int b) { return a == b ? a : (a > b ? a : b); }
+
+/**
+ * Number of black nodes to leaf.
+ *
+ * @param tree The node to traverse down to a leaf.
+ * @return the # of black nodes from the given node to a leaf.
+ */
+static int depth(RBTree *tree) {
+ int total = 1;
+
+ while (tree) {
+ if (tree->colour == black)
+ total += 1;
+ tree = tree->left;
+ }
+ return total;
+}
+
+/**
+ * Determines if a provided subtree is the root.
+ *
+ * @param node The subtree to investigate
+ * @param Returns tree when the node is the root otherwise false.
+ */
+static bool is_root(RBTree *node) { return node->parent == NULL; }
+
+/**
+ * Returns the parent node of a node.
+ *
+ * @param node The node to investigate.
+ * @return The parent of the node or NULL.
+ */
+static RBTree *parent_of(RBTree *node) { return node ? node->parent : NULL; }
+
+/**
+ * Returns the root of a subtree
+ *
+ * @param node The subtree to investigate
+ * @return Returns the root of the subtree
+ */
+static RBTree *root_of(RBTree *node) {
+ RBTree *current = node;
+ RBTree *next = parent_of(current);
+
+ while (next) {
+ current = next;
+ next = parent_of(current);
+ }
+ return current;
+}
+
+/**
+ * Returns the grand parent node of a node.
+ *
+ * @param node The node to investigate.
+ * @return The grand parent of the node or NULL.
+ */
+static RBTree *grand_parent_of(RBTree *node) {
+ return parent_of(parent_of(node));
+}
+
+/**
+ * Returns a sibling node of a given node.
+ *
+ * @param node The node to investigate.
+ * @return The sibling of the node or NULL.
+ */
+static RBTree *sibling_of(RBTree *node) {
+ RBTree *parent = parent_of(node);
+
+ if (!parent)
+ return NULL;
+
+ return node == parent->left ? parent->right : parent->left;
+}
+
+/**
+ * Returns a pibling (aunt/uncle) node of a given node.
+ *
+ * @param node The node to investigate.
+ * @return The pibling of the node or NULL.
+ */
+static RBTree *pibling_of(RBTree *node) { return sibling_of(parent_of(node)); }
+
+static void rb_rotate_left(RBTree *tree) {
+ RBTree *tmp = tree->right;
+ RBTree *parent = parent_of(tree);
+
+ tree->right = tmp->left;
+ tmp->left = tree;
+ tree->parent = tmp;
+
+ if (tree->right)
+ tree->right->parent = tree;
+
+ if (parent) {
+ if (tree == parent->left)
+ parent->left = tmp;
+ else if (tree == parent->right)
+ parent->right = tmp;
+ }
+ tmp->parent = parent;
+}
+
+/**
+ * Performs a right rotation on a subtree
+ *
+ * @param tree The subtree to perform the rotation on
+ */
+static void rb_rotate_right(RBTree *tree) {
+ RBTree *tmp = tree->left;
+ RBTree *parent = parent_of(tree);
+
+ tree->left = tmp->right;
+ tmp->right = tree;
+ tree->parent = tmp;
+
+ if (tree->left)
+ tree->left->parent = tree;
+
+ if (parent) {
+ if (tree == parent->left)
+ parent->left = tmp;
+ else if (tree == parent->right)
+ parent->right = tmp;
+ }
+ tmp->parent = parent;
+}
+
+/**
+ * Performs any repairs necessary on a subtree
+ *
+ * @param tree The subtree to perform a repair on
+ */
+static void repair_from(RBTree *tree) {
+ RBTree *parent = parent_of(tree);
+ RBTree *pibling = pibling_of(tree);
+
+ if (parent == NULL || parent->colour == black) {
+ return;
+ }
+
+ if (pibling && pibling->colour == red) {
+ parent->colour = black;
+ pibling->colour = black;
+ RBTree *grand_parent = grand_parent_of(tree);
+ if (grand_parent->parent)
+ grand_parent->colour = red;
+ repair_from(grand_parent_of(tree));
+ } else {
+ RBTree *grand_parent = grand_parent_of(tree);
+
+ if (!grand_parent)
+ return;
+ if (tree == parent->right && parent == grand_parent->left) {
+ rb_rotate_left(parent);
+ } else if (tree == parent->left && parent == grand_parent->right) {
+ rb_rotate_right(parent);
+ tree = tree->right;
+ }
+
+ parent = parent_of(tree);
+ grand_parent = grand_parent_of(tree);
+
+ if (tree == parent->left) {
+ rb_rotate_right(grand_parent);
+ } else {
+ rb_rotate_left(grand_parent);
+ }
+ parent->colour = black;
+ if (grand_parent->parent)
+ grand_parent->colour = red;
+ }
+}
+
+/**
+ * Compares two integers and returns -1, 0, 1.
+ * If a is equal to b then 0 is returned.
+ * If a is greater than b then 1 is returned.
+ * If a is less than b then -1 is returned.
+ *
+ * @param a An integer
+ * @param b Another integer
+ * @return Returns 0, 1, or -1.
+ */
+static int compare(int a, int b) { return a == b ? 0 : a < b ? -1 : 1; }
+
+/**
+ * Inserts a new node into a subtree.
+ *
+ * @param tree The subtree to attempt to insert a new value into.
+ * @param node The new node to insert.
+ */
+static void insert(RBTree *root, RBTree *node) {
+ if (!root)
+ return;
+
+ if (compare(node->value, root->value) < 0) {
+ if (root->left)
+ insert(root->left, node);
+ else {
+ root->left = node;
+ node->parent = root;
+ }
+ } else {
+ if (root->right)
+ insert(root->right, node);
+ else {
+ root->right = node;
+ node->parent = root;
+ }
+ }
+}
+
+/**
+ * Print a visual representation of a tree.
+ *
+ * @param tree The subtree to print
+ * @param level The level in the tree that this subtree is in
+ */
+static void print_tree(RBTree *tree, int level) {
+ for (int i = 0; i < level; i++)
+ printf(" ");
+
+ if (tree) {
+ printf("(%d%c H:%d)\n", tree->value, tree->colour == red ? 'R' : 'B',
+ rb_tree_height(tree));
+
+ if (!tree->left && !tree->right)
+ return;
+ print_tree(tree->left, level + 1);
+ print_tree(tree->right, level + 1);
+ } else {
+ printf("( )\n");
+ }
+}
+
+/**
+ * Initializes an instance of a tree.
+ *
+ * @param value The value to assign to the new node in the tree.
+ * @param color The colour to assign to the new node in the tree.
+ * @return Returns the new tree node instance.
+ */
+RBTree *rb_tree_initialize_with(int value, enum Colour colour) {
+ RBTree *tree = malloc(sizeof(RBTree));
+ tree->colour = colour;
+ tree->left = NULL;
+ tree->parent = NULL;
+ tree->right = NULL;
+ tree->value = value;
+ return tree;
+}
+
+/**
+ * Initializes an instance of a tree with a default colour of black.
+ *
+ * @param value The value to assign to the new node in the tree.
+ * @return Returns the new tree node instance.
+ */
+RBTree *rb_tree_initialize(int value) {
+ return rb_tree_initialize_with(value, black);
+}
+
+/**
+ * Inserts a new value into a subtree.
+ *
+ * @param tree The subtree to attempt to insert a new value into.
+ * @param value The value to insert.
+ * @return Returns the new root of the subtree.
+ */
+RBTree *rb_tree_insert(RBTree *tree, int value) {
+ if (tree == NULL)
+ return rb_tree_initialize(value);
+
+ RBTree *node = rb_tree_initialize_with(value, red);
+ insert(tree, node);
+ repair_from(node);
+ return root_of(node);
+}
+
+/**
+ * Prints a visual inspection of
+ * a tree for debugging purposes to stdout.
+ *
+ * @param tree The tree to visualize
+ */
+void rb_tree_inspect(RBTree *tree) { print_tree(tree, 0); }
+
+int rb_tree_size(RBTree *tree) {
+ int total = 0;
+ if (tree == NULL)
+ return total;
+ if (tree->left)
+ total += rb_tree_size(tree->left);
+ if (tree->right)
+ total += rb_tree_size(tree->right);
+ return total + 1;
+}
+
+/**
+ * Determines if two trees are equal by verifying
+ * that each descendant node in each subtree have
+ * the same value and colour.
+ *
+ * @param tree A tree to compare
+ * @param other_tree Another tree to compare
+ * @return Returns true when both subtrees are equal otherwise false
+ */
+bool rb_equals(RBTree *tree, RBTree *other_tree) {
+ if (!tree || !other_tree)
+ return tree == other_tree;
+
+ if (tree->parent && !other_tree->parent)
+ return false;
+
+ if (!tree->parent && other_tree->parent)
+ return false;
+
+ if (tree->parent && tree->parent->value != other_tree->parent->value)
+ return false;
+
+ return tree->value == other_tree->value &&
+ tree->colour == other_tree->colour &&
+ rb_equals(tree->left, other_tree->left) &&
+ rb_equals(tree->right, other_tree->right);
+}
+
+/**
+ * Determines if a tree matches the properties
+ * necessary to claim to be a valid Red Black tree.
+ *
+ * 1. root must be black
+ * 2. there are the same # of black nodes on every root to the leaf path.
+ * 3. No two red nodes are adjacent.
+ *
+ * @param tree The tree to investigate
+ * @return Returns true if the tree meets the criteria otherwise false.
+ */
+bool rb_tree_is_valid(RBTree *tree) {
+ if (tree == NULL)
+ return true;
+
+ if (is_root(tree) && tree->colour == red)
+ return false;
+
+ if (tree->colour == red && tree->parent->colour == red)
+ return false;
+
+ if (depth(tree->left) != depth(tree->right))
+ return false;
+
+ return rb_tree_is_valid(tree->left) && rb_tree_is_valid(tree->right);
+}
+
+/**
+ * Returns the height of a subtree.
+ *
+ * @param tree The subtree to investigate
+ * @return Returns the height of the subtree
+ */
+int rb_tree_height(RBTree *tree) {
+ if (!tree)
+ return 1;
+
+ return 1 + max(rb_tree_height(tree->left), rb_tree_height(tree->right));
+}
+
+/**
+ * Searches for a node in a subtree with a particular value.
+ *
+ * @param t The subtree to search.
+ * @param value The value to search for
+ * @returns Returns the node containing the value otherwise NULL
+ */
+RBTree *rb_tree_find(RBTree *t, int value) {
+ if (!t)
+ return NULL;
+
+ int x = compare(value, t->value);
+ return x == 0 ? t : rb_tree_find(x < 0 ? t->left : t->right, value);
+}
src/03/rb_tree.h
@@ -0,0 +1,24 @@
+#include <stdbool.h>
+
+enum Colour {
+ black = 0x01,
+ red = 0x00,
+};
+
+typedef struct rb_node {
+ struct rb_node *left;
+ struct rb_node *parent;
+ struct rb_node *right;
+ enum Colour colour;
+ int value;
+} RBTree;
+
+RBTree *rb_tree_initialize(int value);
+RBTree *rb_tree_initialize_with(int value, enum Colour colour);
+RBTree *rb_tree_insert(RBTree *tree, int value);
+RBTree *rb_tree_find(RBTree *tree, int value);
+bool rb_equals(RBTree *tree, RBTree *other_tree);
+bool rb_tree_is_valid(RBTree *tree);
+int rb_tree_size(RBTree *tree);
+void rb_tree_inspect(RBTree *tree);
+int rb_tree_height(RBTree *tree);
src/03/rb_tree_test.c
@@ -0,0 +1,338 @@
+#include "rb_tree.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+/*
+ * Every node has a colour. red or black
+ * Root of the tree is always black.
+ * There are no two adjacent red nodes. (red node cannot have red parent or
+child)
+ * Every path from root to child NULL node has same # of black nodes.
+ *
+ *
+ * 1. every node is coloured red or black.
+ * 2. All leaves (nils) are black.
+ * 3. Every red node has black children. black nodes can have any color
+children.
+ * 4. From any node, the # of black nodes on any path to the leaves is the same.
+(same # of black nodes from top to bottom)
+
+height: logn if perfectly balanced.
+
+ (B)
+ / \
+ (R) (R)
+ / \ / \
+ (B) (B) (B) (B)
+ / \
+(nil) (nil)
+ */
+
+Ensure(initialize_returns_a_new_tree) {
+ RBTree *tree = rb_tree_initialize(10);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(10));
+ assert_that(tree->colour, is_equal_to(black));
+}
+
+Ensure(insert_returns_a_new_tree_when_null) {
+ RBTree *tree = rb_tree_insert(NULL, 20);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(20));
+ assert_that(tree->colour, is_equal_to(black));
+}
+
+Ensure(insert_adds_a_new_item_to_right_subtree) {
+ RBTree *tree = rb_tree_initialize(10);
+
+ tree = rb_tree_insert(tree, 20);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(10));
+ assert_that(tree->colour, is_equal_to(black));
+ assert_that(tree->right, is_not_equal_to(NULL));
+ assert_that(tree->right->value, is_equal_to(20));
+}
+
+Ensure(insert_adds_a_new_item_to_left_subtree) {
+ RBTree *tree = rb_tree_initialize(20);
+
+ tree = rb_tree_insert(tree, 10);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(20));
+ assert_that(tree->colour, is_equal_to(black));
+ assert_that(tree->left, is_not_equal_to(NULL));
+ assert_that(tree->left->value, is_equal_to(10));
+}
+
+Ensure(rb_tree_insert_performs_a_right_rotation) {
+ /*
+ (30) (20:b)
+ / / \
+ (20) -> (10:r) (30:r)
+ /
+ (10)
+
+ */
+ RBTree *tree = rb_tree_initialize(30);
+
+ tree = rb_tree_insert(tree, 20);
+ tree = rb_tree_insert(tree, 10);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(20));
+ assert_that(tree->colour, is_equal_to(black));
+
+ assert_that(tree->left->value, is_equal_to(10));
+ assert_that(tree->left->colour, is_equal_to(red));
+
+ assert_that(tree->right->value, is_equal_to(30));
+ assert_that(tree->right->colour, is_equal_to(red));
+
+ assert_that(rb_tree_is_valid(tree), is_equal_to(true));
+}
+
+Ensure(rb_tree_insert_performs_a_left_rotation) {
+ /*
+ (10) (20:b)
+ \ / \
+ (20) -> (10:r) (30:r)
+ \
+ (30)
+ */
+
+ RBTree *tree = rb_tree_initialize(10);
+ tree = rb_tree_insert(tree, 20);
+ tree = rb_tree_insert(tree, 30);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(20));
+ assert_that(tree->colour, is_equal_to(black));
+ assert_that(tree->left->value, is_equal_to(10));
+ assert_that(tree->left->colour, is_equal_to(red));
+ assert_that(tree->right->value, is_equal_to(30));
+ assert_that(tree->right->colour, is_equal_to(red));
+
+ assert_that(rb_tree_is_valid(tree), is_equal_to(true));
+}
+
+Ensure(rb_tree_insert_repaints_the_new_node) {
+ /*
+ (20:b) (20:b)
+ / \ / \
+ (10:r) (30:r) --> (10:b) (30:b)
+ / /
+ (5:r) (5:r)
+ */
+
+ RBTree *tree = rb_tree_initialize(20);
+ tree = rb_tree_insert(tree, 10);
+ tree = rb_tree_insert(tree, 30);
+ tree = rb_tree_insert(tree, 5);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(20));
+ assert_that(tree->colour, is_equal_to(black));
+
+ assert_that(tree->left->value, is_equal_to(10));
+ assert_that(tree->left->colour, is_equal_to(black));
+
+ assert_that(tree->left->left->value, is_equal_to(5));
+ assert_that(tree->left->left->colour, is_equal_to(red));
+
+ assert_that(tree->right->value, is_equal_to(30));
+ assert_that(tree->right->colour, is_equal_to(black));
+
+ assert_that(rb_tree_is_valid(tree), is_equal_to(true));
+}
+
+Ensure(rb_tree_insert_handles_large_trees) {
+ RBTree *tree = NULL;
+ int n = 100;
+
+ for (int i = n; i > 0; i--)
+ tree = rb_tree_insert(tree, i);
+
+ assert_that(tree, is_not_equal_to(NULL));
+ assert_that(tree->value, is_equal_to(69));
+ assert_that(tree->colour, is_equal_to(black));
+
+ assert_that(rb_tree_size(tree), is_equal_to(n));
+ assert_that(rb_tree_is_valid(tree), is_equal_to(true));
+}
+
+Ensure(equals_returns_false_when_tree_is_NULL) {
+ assert_that(rb_equals(NULL, rb_tree_initialize(10)), is_equal_to(false));
+}
+
+Ensure(equals_returns_false_when_other_tree_is_NULL) {
+ assert_that(rb_equals(rb_tree_initialize(10), NULL), is_equal_to(false));
+}
+
+Ensure(equals_returns_true_when_both_trees_are_NULL) {
+ assert_that(rb_equals(NULL, NULL), is_equal_to(true));
+}
+
+Ensure(equals_returns_false_when_tree_has_one_node) {
+ RBTree *tree = rb_tree_initialize(20);
+ RBTree *other_tree = rb_tree_initialize(10);
+
+ assert_that(rb_equals(tree, other_tree), is_equal_to(false));
+}
+
+Ensure(equals_returns_false_when_tree_has_one_node_with_different_colours) {
+ RBTree *tree = rb_tree_initialize(20);
+ RBTree *other_tree = rb_tree_initialize(20);
+
+ tree->colour = black;
+ other_tree->colour = red;
+
+ assert_that(rb_equals(tree, other_tree), is_equal_to(false));
+}
+
+Ensure(equals_returns_true_when_tree_has_one_node) {
+ RBTree *tree = rb_tree_initialize(20);
+ RBTree *other_tree = rb_tree_initialize(20);
+
+ assert_that(rb_equals(tree, other_tree), is_equal_to(true));
+}
+
+Ensure(equals_returns_true_when_root_and_left_subtree_are_equal) {
+ RBTree *tree = rb_tree_initialize(20);
+ tree = rb_tree_insert(tree, 10);
+
+ RBTree *other_tree = rb_tree_initialize(20);
+ other_tree = rb_tree_insert(other_tree, 10);
+
+ assert_that(rb_equals(tree, other_tree), is_equal_to(true));
+}
+
+Ensure(equals_returns_false_when_root_and_left_subtree_are_not_equal) {
+ RBTree *tree = rb_tree_initialize(20);
+ tree = rb_tree_insert(tree, 10);
+
+ RBTree *other_tree = rb_tree_initialize(20);
+ other_tree = rb_tree_insert(other_tree, 15);
+
+ assert_that(rb_equals(tree, other_tree), is_equal_to(false));
+}
+
+Ensure(equals_returns_false_when_root_and_right_subtree_are_not_equal) {
+ RBTree *tree = rb_tree_initialize(20);
+ tree = rb_tree_insert(tree, 30);
+
+ RBTree *other_tree = rb_tree_initialize(20);
+ other_tree = rb_tree_insert(other_tree, 25);
+
+ assert_that(rb_equals(tree, other_tree), is_equal_to(false));
+}
+
+Ensure(equals_returns_false_when_parent_is_not_equal) {
+ RBTree *tree = rb_tree_initialize(20);
+ tree = rb_tree_insert(tree, 30);
+
+ RBTree *other_tree = rb_tree_initialize(20);
+ other_tree = rb_tree_insert(other_tree, 30);
+
+ other_tree->right->parent = NULL;
+
+ assert_that(rb_equals(tree, other_tree), is_equal_to(false));
+ assert_that(rb_equals(other_tree, tree), is_equal_to(false));
+}
+
+Ensure(is_valid_returns_false_when_root_is_red) {
+ RBTree *tree = rb_tree_initialize(20);
+ tree->colour = red;
+
+ assert_that(rb_tree_is_valid(tree), is_equal_to(false));
+}
+
+Ensure(is_valid_returns_false_when_red_node_has_red_child) {
+ RBTree *tree = NULL;
+
+ for (int i = 10; i > 0; i--)
+ tree = rb_tree_insert(tree, i);
+
+ tree->left->colour = red;
+ tree->left->left->colour = red;
+
+ assert_that(rb_tree_is_valid(tree), is_equal_to(false));
+}
+
+Ensure(
+ is_valid_returns_false_when_each_path_to_leaves_does_not_contain_the_same_number_of_black_nodes) {
+ RBTree *tree = NULL;
+
+ for (int i = 10; i > 0; i--)
+ tree = rb_tree_insert(tree, i);
+
+ tree->left->left->colour = black;
+ assert_that(rb_tree_is_valid(tree), is_equal_to(false));
+}
+
+Ensure(is_valid_return_true) {
+ RBTree *tree = NULL;
+
+ for (int i = 0; i < 100; ++i)
+ tree = rb_tree_insert(tree, i);
+
+ assert_that(rb_tree_is_valid(tree), is_equal_to(true));
+}
+
+Ensure(height_returns_one) {
+ assert_that(rb_tree_height(NULL), is_equal_to(1));
+}
+
+Ensure(height_returns_three_when_left_subtree_is_present) {
+ RBTree *tree = rb_tree_initialize(10);
+ tree = rb_tree_insert(tree, 5);
+
+ assert_that(rb_tree_height(tree), is_equal_to(3));
+}
+
+Ensure(height_returns_three_when_right_subtree_is_present) {
+ RBTree *tree = rb_tree_initialize(10);
+ tree = rb_tree_insert(tree, 15);
+
+ assert_that(rb_tree_height(tree), is_equal_to(3));
+}
+
+TestSuite *rb_tree_tests() {
+ TestSuite *x = create_test_suite();
+
+ add_test(x, initialize_returns_a_new_tree);
+
+ add_test(x, insert_returns_a_new_tree_when_null);
+ add_test(x, insert_adds_a_new_item_to_right_subtree);
+ add_test(x, insert_adds_a_new_item_to_left_subtree);
+ add_test(x, rb_tree_insert_performs_a_right_rotation);
+ add_test(x, rb_tree_insert_performs_a_left_rotation);
+ add_test(x, rb_tree_insert_repaints_the_new_node);
+ add_test(x, rb_tree_insert_handles_large_trees);
+
+ add_test(x, equals_returns_false_when_tree_is_NULL);
+ add_test(x, equals_returns_false_when_other_tree_is_NULL);
+ add_test(x, equals_returns_true_when_both_trees_are_NULL);
+ add_test(x, equals_returns_false_when_tree_has_one_node);
+ add_test(x,
+ equals_returns_false_when_tree_has_one_node_with_different_colours);
+ add_test(x, equals_returns_true_when_tree_has_one_node);
+ add_test(x, equals_returns_true_when_root_and_left_subtree_are_equal);
+ add_test(x, equals_returns_false_when_root_and_left_subtree_are_not_equal);
+ add_test(x, equals_returns_false_when_root_and_right_subtree_are_not_equal);
+ add_test(x, equals_returns_false_when_parent_is_not_equal);
+
+ add_test(x, is_valid_returns_false_when_root_is_red);
+ add_test(x, is_valid_returns_false_when_red_node_has_red_child);
+ add_test(
+ x,
+ is_valid_returns_false_when_each_path_to_leaves_does_not_contain_the_same_number_of_black_nodes);
+ add_test(x, is_valid_return_true);
+
+ add_test(x, height_returns_one);
+ add_test(x, height_returns_three_when_left_subtree_is_present);
+ add_test(x, height_returns_three_when_right_subtree_is_present);
+ return x;
+}
src/03/README.md
@@ -0,0 +1,1011 @@
+# Learning Profile for Assignment #3
+## Computer Science 272: Data Structures and Algorithms
+
+* Name: Mo Khan
+* Student ID: 3431709
+* https://github.com/mokhan/comp-272/tree/master/src/03/README.md
+
+## Question 1
+### Problem Statement
+
+Illustrate that the nodes of any AVL tree T can be
+colored "red" and "black" so that T becomes a
+red-black tree.
+
+```plaintext
+ AVL Tree Red-Black Tree
+ (20:3) (20:b)
+ / \ --> / \
+ (15:2) (30:2) (15:b) (30:b)
+ / \ \ / \ \
+(10:1) (17:1) (35:1) (10:r) (17:r) (35:r)
+```
+
+* perform pre order traversal
+* assign colour of Red/Black node based on height of each AVL node
+
+```plaintext
+Step 1:
+ (20:b)
+
+Step 2:
+ (20:b)
+ /
+ (15:b)
+
+Step 3:
+ (20:b)
+ /
+ (15:b)
+ /
+ (10:r)
+
+Step 4:
+ (20:b)
+ /
+ (15:b)
+ / \
+ (10:r) (17:r)
+
+Step 5:
+ (20:b)
+ / \
+ (15:b) (30:b)
+ / \
+ (10:r) (17:r)
+
+Step 6:
+ (20:b)
+ / \
+ (15:b) (30:b)
+ / \ \
+ (10:r) (17:r) (35:r)
+```
+
+### Description of the Code
+
+The function `avl_tree_to_rb_tree` provides an
+implementation of this. To accomplish this
+the code makes two passes down the tree. The
+first pass it used to build a clone of the
+AVL tree as a Red-Black tree with all nodes coloured
+black. The second pass traverses the red-black
+tree and applies the appropriate colour to
+each node in the function `change_colour`.
+
+If the height of the left subtree is less
+than the height of hte right subtree or
+the height is odd then the left child is
+coloured black otherwise red.
+
+The same is applied to the right subtree.
+
+```c
+change_colour(tree->left, left_height < right_height || is_odd(left_height) ? black : red);
+change_colour(tree->right, right_height < left_height || is_odd(right_height) ? black : red);
+```
+
+
+## Question 2
+### Problem Statement
+
+Illustrate that via AVL single rotation, any binary search tree T1 can be
+transformed into another search tree T2 (with the same items).
+
+Left rotation:
+
+```plaintext
+ (10) (20)
+ \ / \
+ (20) -> (10) (30)
+ \
+ (30)
+```
+
+Right rotation:
+
+```plaintext
+ (30) (20)
+ / / \
+ (20) --> (10) (30)
+ /
+(10)
+```
+
+Left-Right rotation:
+
+```plaintext
+ (30) (20)
+ / / \
+(10) -> (10) (30)
+ \
+ (20)
+```
+
+Right-Left rotation:
+
+```plaintext
+(10) (20)
+ \ / \
+ (30) --> (10) (30)
+ /
+(20)
+```
+
+Give an algorithm to perform this transformation using O(N log N) rotation on average.
+
+See `./avl_tree.c`.
+
+## Question 3
+### Problem Statement
+
+Suppose you are given two sequences S1 and S2 of `n` elements, possibly
+containing duplicates, on which a total order relation is defined.
+
+1. Describe an efficient algorithm for determining if S1 and S2 contain the same set of elements.
+
+Since S1 and S2 has a total order relation defined this means
+that the data is sorted in both sequences.
+
+To tell if the S1 and S2 contain the same set of elements we can use two pointers
+to walk through each item in each sequence one step at a time to compare the values
+at each index to ensure they are a match. As soon as we detect a mismatch
+we know that the sequences do not contain the same set of elements. If we can
+iterate to the end of both sequences at the same time then we have a match.
+
+1. Analyze the running time of this method.
+
+The time complexity is dependent on the size of `n` elements and is
+therefore a linear time algorithm `O(n)`.
+
+The space complexity is constant, `O(1)`, because only two pointers
+are needed to walk through both sequences. The amount of space required
+to perform this algorithm does not change as the input size of `n` changes.
+
+## Question 4
+### Problem Statement
+
+Given sequence 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, sort the sequence using the
+following algorithms, and illustrate the details of the execution of the
+algorithms:
+
+a. merge-sort algorithm.
+
+```plaintext
+[3,1,4,1,5,9,2,6,5,3,5,]
+[3,1,4,1,5,9,]
+[3,1,4,]
+[3,1,]
+[3,]
+[3,1,]
+[1,3,4,]
+[1,3,4,1,5,9,]
+[1,3,4,1,5,]
+[1,3,4,1,]
+[1,3,4,1,5,]
+[1,3,4,1,5,9,]
+[1,1,3,4,5,9,2,6,5,3,5,]
+[1,1,3,4,5,9,2,6,5,]
+[1,1,3,4,5,9,2,6,]
+[1,1,3,4,5,9,2,]
+[1,1,3,4,5,9,2,6,]
+[1,1,3,4,5,9,2,6,5,]
+[1,1,3,4,5,9,2,5,6,3,5,]
+[1,1,3,4,5,9,2,5,6,3,]
+[1,1,3,4,5,9,2,5,6,3,5,]
+```
+
+b. quick-sort algorithm.
+* Choose a partitioning strategy you like to pick a pivot element from the sequence.
+* Analyze how different portioning strategies may impact on the performance of the sorting algorithm.
+
+For choosing a pivot I chose to use the value in the last element of the sequence.
+Alternative, strategies include choosing a random pivot in each sub-sequence.
+
+Using the last item in the sub-sequence as the pivot:
+
+```plaintext
+[3,1,4,1,5,9,2,6,5,3,]
+[3,1,4,1,2,]
+[1,1,]
+[1,]
+[]
+[1,]
+[1,1,]
+[1,1,2,3,4,]
+[1,1,2,]
+[1,1,2,3,3,]
+[1,1,2,3,3,4,5,6,5,9,]
+[1,1,2,3,3,4,]
+[1,1,2,3,3,4,5,5,5,9,]
+[1,1,2,3,3,4,5,5,]
+[1,1,2,3,3,4,5,5,5,6,]
+```
+
+## Question 5
+### Problem Statement
+
+Given the graph shown below, answer the following questions:
+
+1. Illustrate the sequence of vertices of this graph visited using depth-first search traversal starting at vertex `g`.
+1. Illustrate the sequence of vertices of this graph visited using breadth-first search traversal starting at vertex `b`.
+1. Illustrate adjacency list representation and adjacency matrix representation, respectively, for this graph.
+ * What are the advantages and disadvantages of those two representations?
+1. Describe an algorithm to find in the graph a path illustrated below that goes through every edge exactly once in each direction.
+
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+#### Depth First Traversal
+
+Order: g, h, o, p, l, k, n, i, m, j, f, c, d, b, a, e
+
+1. [g]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (*)/--(h)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+2. [g, h]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+3. [g, h, o]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(*)---(p)
+```
+
+4. [g, h, o, p]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(*)---(*)
+```
+
+5. [g, h, o, p, l]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (*)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(*)---(*)
+```
+
+6. [g, h, o, p, l, k]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(i)---(j)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(*)---(*)
+```
+
+7. [g, h, o, p, l, k, n]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(i)---(j)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(m) \(*)---(*)---(*)
+```
+
+8. [g, h, o, p, l, k, n, i]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(j)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(m) \(*)---(*)---(*)
+```
+
+9. [g, h, o, p, l, k, n, i, m]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(j)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(*)
+```
+
+10. [g, h, o, p, l, k, n, i, m, j]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(*)
+```
+
+11. [g, h, o, p, l, k, n, i, m, j, f]
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(*)
+```
+
+12. [g, h, o, p, l, k, n, i, m, j, f, c]
+```plaintext
+(a)---(b)---(*)---(d)
+ | \ / /
+ | \ / /
+(e) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(*)
+```
+
+13. [g, h, o, p, l, k, n, i, m, j, f, c, d]
+```plaintext
+(a)---(b)---(*)---(*)
+ | \ / /
+ | \ / /
+(e) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(*)
+```
+
+14. [g, h, o, p, l, k, n, i, m, j, f, c, d, b]
+```plaintext
+(a)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(e) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(*)
+```
+
+15. [g, h, o, p, l, k, n, i, m, j, f, c, d, b, a]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(e) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(*)
+```
+
+16. [g, h, o, p, l, k, n, i, m, j, f, c, d, b, a, e]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(*)
+```
+
+#### Breadth First Traversal
+
+Order: [b, a, f, c, e, j, d, i, g, m, n, h, k, o, p, l]
+
+1. [b]
+```plaintext
+(a)---(*)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+2. [b, a]
+```plaintext
+(*)---(*)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+3. [b, a, f]
+```plaintext
+(*)---(*)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(*)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+4. [b, a, f, c]
+```plaintext
+(*)---(*)---(*)---(d)
+ | \ / /
+ | \ / /
+(e) \(*)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+5. [b, a, f, c, e]
+```plaintext
+(*)---(*)---(*)---(d)
+ | \ / /
+ | \ / /
+(*) \(*)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+6. [b, a, f, c, e, j]
+```plaintext
+(*)---(*)---(*)---(d)
+ | \ / /
+ | \ / /
+(*) \(*)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(*)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+7. [b, a, f, c, e, j, d]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(*)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+8. [b, a, f, c, e, j, d, i]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(*)---(*)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+9. [b, a, f, c, e, j, d, i, g]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (*)/--(h)
+ | | / | /
+ | | / | /
+(*)---(*)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+10. [b, a, f, c, e, j, d, i, g, m]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (*)/--(h)
+ | | / | /
+ | | / | /
+(*)---(*)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(*) \(n)---(o)---(p)
+```
+
+11. [b, a, f, c, e, j, d, i, g, m, n]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (*)/--(h)
+ | | / | /
+ | | / | /
+(*)---(*)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(o)---(p)
+```
+
+12. [b, a, f, c, e, j, d, i, g, m, n, h]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(o)---(p)
+```
+
+13. [b, a, f, c, e, j, d, i, g, m, n, h, k]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (l)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(o)---(p)
+```
+
+14. [b, a, f, c, e, j, d, i, g, m, n, h, k, o]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (l)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(p)
+```
+
+15. [b, a, f, c, e, j, d, i, g, m, n, h, k, o, p]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (l)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(*)
+```
+
+16. [b, a, f, c, e, j, d, i, g, m, n, h, k, o, p, l]
+```plaintext
+(*)---(*)---(*)---(*)
+ | \ / /
+ | \ / /
+(*) \(*)/ (*)/--(*)
+ | | / | /
+ | | / | /
+(*)---(*)/ (*) / (*)
+ | \ | / |
+ | \ |/ |
+(*) \(*)---(*)---(*)
+```
+
+#### Adjacency List
+
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+
+(a) -> [b, e, f]
+(b) -> [a, f]
+(c) -> [b, d, f]
+(d) -> [c, g]
+(e) -> [a, i]
+(f) -> [a, c, j]
+(g) -> [d, h, j, k]
+(h) -> [g, o]
+(i) -> [e, j, m, n]
+(j) -> [f, g, i]
+(k) -> [g, o]
+(l) -> [p]
+(m) -> [i]
+(n) -> [i, o]
+(o) -> [k, n, p]
+(p) -> [l, o]
+```
+
+Good:
+
+* Space efficient because no space is wasted for edges that do not exist.
+
+Bad:
+
+* A lookup to determine if two vertexes are connected requires a linear time lookup due to the size of the list for a single edge. `O(n)`.
+
+#### Adjacency Matrix
+
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+```plaintext
+-----------------------------------
+| |a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|
+|a|0|1|0|0|1|1|0|0|0|0|0|0|0|0|0|0|
+|b|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|c|0|1|0|1|0|1|0|0|0|0|0|0|0|0|0|0|
+|d|0|0|1|0|0|0|1|0|0|0|0|0|0|0|0|0|
+|e|1|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|
+|f|1|0|1|0|0|0|0|0|0|1|0|0|0|0|0|0|
+|g|0|0|0|1|0|0|0|1|0|1|1|0|0|0|0|0|
+|h|0|0|0|0|0|0|1|0|0|0|0|0|0|0|1|0|
+|i|0|0|0|0|1|0|0|0|0|1|0|0|1|1|0|0|
+|j|0|0|0|0|0|1|1|0|1|0|0|0|0|0|0|0|
+|k|0|0|0|0|0|0|1|0|0|0|0|0|0|0|1|0|
+|l|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|
+|m|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|
+|n|0|0|0|0|0|0|0|0|1|0|0|0|0|0|1|0|
+|o|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|1|
+|p|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|
+-----------------------------------
+```
+
+Good:
+
+* constant time lookup to see if two vertexes are connected `O(1)`
+
+Bad:
+
+* space inefficient `O(n^2)`
+
+
+An adjacency matrix might be a better choice when space is less important
+than fast lookups. An adjacency list may be a better choice if space is
+a higher priority concern than time.
+
+#### Traverse Every Edge
+
+To traverse every edge in both directions we can use an adjacency matrix
+and iterate through every cell in the matrix. If the cell contains a 1 to
+indicate an edge than we know that we can traverse from the edge at
+that row and column. Both directions will be represented in different cells
+in the matrix.
+
+When we visit each cell in the matrix we can flip the 1 to a 0 to ensure that
+we do not revisit a visited edge.
+
+1. Start at any vertex
+1. Iterate through list of edges.
+1. If the vertex on the other end of the edge has not been visited yet then visit it and loop until all edges are exhausted for the vertex.
+1. Remove the edge from the matrix when visiting a node
+1. Backtrack to previous vertex, and remove the edge.
+1. Visit any edge where you can backtrack safely.
+
+An example of this algorithm can be found in `./matrix.c` with accompanying tests in `./matrix_test.c`.
+
+The graph to traverse is:
+
+```plaintext
+(a)---(b)---(c)---(d)
+ | \ / /
+ | \ / /
+(e) \(f)/ (g)/--(h)
+ | | / | /
+ | | / | /
+(i)---(j)/ (k) / (l)
+ | \ | / |
+ | \ |/ |
+(m) \(n)---(o)---(p)
+```
+
+We can build a matrix that will look like the following:
+
+```bash
+| |a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|
+|a|0|1|0|0|1|1|0|0|0|0|0|0|0|0|0|0|
+|b|1|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|c|0|1|0|1|0|1|0|0|0|0|0|0|0|0|0|0|
+|d|0|0|1|0|0|0|1|0|0|0|0|0|0|0|0|0|
+|e|1|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|
+|f|1|0|1|0|0|0|0|0|0|1|0|0|0|0|0|0|
+|g|0|0|0|1|0|0|0|1|0|1|1|0|0|0|0|0|
+|h|0|0|0|0|0|0|1|0|0|0|0|0|0|0|1|0|
+|i|0|0|0|0|1|0|0|0|0|1|0|0|1|1|0|0|
+|j|0|0|0|0|0|1|1|0|1|0|0|0|0|0|0|0|
+|k|0|0|0|0|0|0|1|0|0|0|0|0|0|0|1|0|
+|l|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|
+|m|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|
+|n|0|0|0|0|0|0|0|0|1|0|0|0|0|0|1|0|
+|o|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|1|
+|p|0|0|0|0|0|0|0|0|0|0|0|1|0|0|1|0|
+```
+
+The order of traversal will be:
+
+```plaintext
+->(a)->(b)->(c)->(d)->(g)->(h)->(o)->(k)->(g)->(j)->(f)->(a)->(e)->(i)->(m)-
+ |
+|---------------------------------------------------------------------------
+->(i)->(n)->(o)->(p)->(l)->(p)->(o)->(n)->(i)->(j)->(i)->(e)->(a)->(f)->(c)-
+ |
+|---------------------------------------------------------------------------
+->(f)->(j)->(g)->(k)->(o)->(h)->(g)->(d)->(c)->(b)->(a)
+```
+
+After the traversal the matrix will have zero edges.
+
+```bash
+| |a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|
+|a|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|b|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|c|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|d|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|e|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|f|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|g|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|h|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|i|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|j|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|k|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|l|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|m|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|n|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|o|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+|p|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
+```
+
+## Question 6
+### Problem Statement
+
+Why does the method `remove(x)` in the `RedBlackTree` implementation
+perform the assignment `u:parent = w:parent?`
+Shouldn’t this already be done by the call to `splice(w)`?
+
+It is possible that more than one rotation needs to occur so assigning the new parent
+is necessary.
+
+```java
+boolean remove(T x)
+{
+ Node<T> u = findLast(x);
+ if (u == nil || compare(u.x, x) != 0)
+ return false;
+ Node<T> w = u.right;
+ if (w == nil) {
+ w = u;
+ u = w.left;
+ } else {
+ while (w.left != nil)
+ w = w.left;
+ u.x = w.x;
+ u = w.right;
+ }
+ splice(w);
+ u.colour += w.colour;
+ u.parent = w.parent;
+ removeFixup(u);
+ return true;
+}
+
+void removeFixup(Node<T> u) {
+ while (u.colour > black) {
+ if (u == r) {
+ u.colour = black;
+ } else if (u.parent.left.colour == red) {
+ u = removeFixupCase1(u);
+ } else if (u == u.parent.left) {
+ u = removeFixupCase2(u);
+ } else {
+ u = removeFixupCase3(u);
+ }
+ }
+ if (u != r) {
+ Node<T> w = u.parent;
+ if (w.right.colour == red && w.left.colour == black) {
+ flipLeft(w);
+ }
+ }
+}
+```
+Source [Open Data Structures](https://www.aupress.ca/app/uploads/120226_99Z_Morin_2013-Open_Data_Structures.pdf)
+
+## Question 7
+### Problem Statement
+
+Implement the `remove(u)` method, that removes the node `u` from a
+`MeldableHeap`. This method should run in `O(log n)` expected time.
+
+```java
+class MeldableHeap {
+ Node<T> merge(Node<T> h1, Node<T> h2) {
+ if (h1 == nil) return h2;
+ if (h2 == nil) return h1;
+ if (compare(h2.x, h1.x) < 0) return merge(h2, h1);
+
+ if (rand.nextBoolean()) {
+ h1.left = merge(h1.left, h2);
+ h1.left.parent = h1;
+ } else {
+ h1.right = merge(h1.right, h2);
+ h1.right.parent = h1;
+ }
+ return h1;
+ }
+
+ boolean add(T x) {
+ Node<T> u = newNode();
+ u.x = x;
+ r = merge(u, r);
+ r.parent = nil;
+ n++;
+ return true;
+ }
+
+ T remove() {
+ T x = r.x;
+ r = merge(r.left, r.right);
+ if (r != nil) r.parent = nil;
+ n--;
+ return x;
+ }
+}
+```
+[Source](https://www.aupress.ca/app/uploads/120226_99Z_Morin_2013-Open_Data_Structures.pdf)
+
+An implementation of `meldable_heap_remove(u)` can be found in `./meldable_heap.c`.
+
+## Question 8
+### Problem Statement
+
+Prove that a binary tree with `k` leaves has height at least `log k`.
+
+The proof can be derived with the following.
+Suppose we have a function `h` that takes input `k`
+and returns a tree with `k` leaves.
+
+For each positive natural number we can
+assert that the height of the tree must be greater
+than or equal to `log2(k)`.
+
+```plaintext
+for each positive natural number
+ assert(height(h(k)) >= log2(k))
+```
+
+An example test is provided in `btree_test.c` that
+asserts that this holds true for the first
+500 positive integers.
+
+```c
+for (int k = 0; k < 500; ++k)
+ assert_that(btree_height(btree_generate(k)) >= log2(k), is_equal_to(true));
+```
src/03/sort.c
@@ -0,0 +1,133 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * Prints a visual dump of an array of
+ * items to stdout out for debugging.
+ *
+ * @param items The items to inspect
+ * @param n The total # of items in the array.
+ */
+static void dump(int *items, int n) {
+ printf("[");
+ for (int i = 0; i < n; ++i)
+ printf("%d,", items[i]);
+ printf("]\n");
+}
+
+/**
+ * Merges two subsequences of an array.
+ *
+ * @params items A pointer to the start of an array of items
+ * @param min The starting index of the left sub sequence.
+ * @param mid The starting index of the right sub sequence.
+ * @param max The ending index of the right sub sequence.
+ */
+static void _merge(int *items, int min, int mid, int max) {
+ int length = (max - min) + 1;
+ int tmp[length];
+ int j = min, k = mid;
+
+ for (int i = 0; i < length; i++) {
+ if (j < mid && k <= max)
+ if (items[j] < items[k])
+ tmp[i] = items[j++];
+ else
+ tmp[i] = items[k++];
+ else if (j >= mid)
+ tmp[i] = items[k++];
+ else
+ tmp[i] = items[j++];
+ }
+
+ for (int i = 0; i < length; i++)
+ items[min + i] = tmp[i];
+}
+
+/**
+ * Performs a recursive merge sort of items in an array.
+ *
+ * @param items An array of integers.
+ * @param min The starting index of a subsequence to sort
+ * @param max The ending index of a subsequence to sort
+ */
+static void _merge_sort(int *items, int min, int max) {
+ if (min >= max)
+ return;
+
+ int mid = min + (max - min) / 2;
+ _merge_sort(items, min, mid);
+ _merge_sort(items, mid + 1, max);
+ _merge(items, min, mid + 1, max);
+}
+
+/**
+ * Partitions a sequence into two subsequences.
+ *
+ * @param items An array of integers to partition
+ * @param min The starting index of the sequence to partition
+ * @param max The ending index of the sequence to partition
+ * @return Returns the index that can be used as the partition point for the
+ * sequence.
+ */
+static int partition(int *items, int min, int max) {
+ int pivot = items[max];
+ int index = min - 1;
+ int tmp;
+
+ for (int j = min; j < max; j++) {
+ if (items[j] < pivot) {
+ index++;
+ tmp = items[index];
+ items[index] = items[j];
+ items[j] = tmp;
+ }
+ }
+ tmp = items[index + 1];
+ items[index + 1] = items[max];
+ items[max] = tmp;
+
+ return index + 1;
+}
+
+/**
+ * Performs a recursive quick sort on an array of items.
+ *
+ * @param items An array of integers
+ * @param min The starting index of a subsequence to sort
+ * @param max The ending index of a subsequence to sort
+ */
+static void _quick_sort(int *items, int min, int max) {
+ if (min >= max)
+ return;
+
+ int index = partition(items, min, max);
+ _quick_sort(items, min, index - 1);
+ _quick_sort(items, index + 1, max);
+}
+
+/**
+ * Performs a merge sort on an array of integers.
+ *
+ * @param items An array of integers
+ * @param length The # of items in the array of integers
+ */
+void merge_sort(int *items, int length) {
+ if (!items || length <= 0)
+ return;
+
+ _merge_sort(items, 0, length - 1);
+}
+
+/**
+ * Performs a quick sort on an array of integers.
+ *
+ * @param items An array of integers
+ * @param length The # of items in the array of integers
+ */
+void quick_sort(int *items, int length) {
+ if (!items || length <= 0)
+ return;
+
+ _quick_sort(items, 0, length - 1);
+}
src/03/sort.h
@@ -0,0 +1,2 @@
+void merge_sort(int *items, int length);
+void quick_sort(int *items, int length);
src/03/sort_test.c
@@ -0,0 +1,136 @@
+#include "sort.h"
+#include <cgreen/cgreen.h>
+#include <string.h>
+
+Ensure(one_equals_one) { assert_that(1, is_equal_to(1)); }
+
+Ensure(merge_sort_sorts_a_null_list) { merge_sort(NULL, 0); }
+
+Ensure(merge_sort_sorts_an_empty_list) {
+ int items[] = {};
+
+ merge_sort(items, 0);
+
+ assert_that(sizeof(items), is_equal_to(0));
+}
+
+Ensure(merge_sort_sorts_a_list_with_one_item) {
+ int items[] = {100};
+
+ merge_sort(items, 1);
+
+ assert_that(sizeof(items), is_equal_to(sizeof(int)));
+ assert_that(items[0], is_equal_to(100));
+}
+
+Ensure(merge_sort_sorts_a_list_with_two_items) {
+ int items[] = {100, 10};
+
+ merge_sort(items, 2);
+
+ assert_that(items[0], is_equal_to(10));
+ assert_that(items[1], is_equal_to(100));
+}
+
+Ensure(merge_sort_sorts_three_unique_items) {
+ int items[] = {3, 1, 4};
+
+ merge_sort(items, sizeof(items) / sizeof(int));
+
+ assert_that(items[0], is_equal_to(1));
+ assert_that(items[1], is_equal_to(3));
+ assert_that(items[2], is_equal_to(4));
+}
+
+Ensure(merge_sort_sorts_many_items) {
+ int items[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
+
+ merge_sort(items, sizeof(items) / sizeof(int));
+
+ assert_that(items[0], is_equal_to(1));
+ assert_that(items[1], is_equal_to(1));
+ assert_that(items[2], is_equal_to(2));
+ assert_that(items[3], is_equal_to(3));
+ assert_that(items[4], is_equal_to(3));
+ assert_that(items[5], is_equal_to(4));
+ assert_that(items[6], is_equal_to(5));
+ assert_that(items[7], is_equal_to(5));
+ assert_that(items[8], is_equal_to(5));
+ assert_that(items[9], is_equal_to(6));
+ assert_that(items[10], is_equal_to(9));
+}
+
+Ensure(quick_sort_sorts_a_null_list) { quick_sort(NULL, 0); }
+
+Ensure(quick_sort_sorts_an_empty_list) {
+ int items[] = {};
+
+ quick_sort(items, 0);
+
+ assert_that(sizeof(items), is_equal_to(0));
+}
+
+Ensure(quick_sort_sorts_a_list_with_one_item) {
+ int items[] = {100};
+
+ quick_sort(items, 1);
+
+ assert_that(items[0], is_equal_to(100));
+}
+
+Ensure(quick_sort_sorts_a_list_with_two_items) {
+ int items[] = {100, 10};
+
+ quick_sort(items, 2);
+
+ assert_that(items[0], is_equal_to(10));
+ assert_that(items[1], is_equal_to(100));
+}
+
+Ensure(quick_sort_sorts_three_unique_items) {
+ int items[] = {3, 1, 4};
+
+ quick_sort(items, sizeof(items) / sizeof(int));
+
+ assert_that(items[0], is_equal_to(1));
+ assert_that(items[1], is_equal_to(3));
+ assert_that(items[2], is_equal_to(4));
+}
+
+Ensure(quick_sort_sorts_many_items) {
+ int items[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
+
+ quick_sort(items, sizeof(items) / sizeof(int));
+
+ assert_that(items[0], is_equal_to(1));
+ assert_that(items[1], is_equal_to(1));
+ assert_that(items[2], is_equal_to(2));
+ assert_that(items[3], is_equal_to(3));
+ assert_that(items[4], is_equal_to(3));
+ assert_that(items[5], is_equal_to(4));
+ assert_that(items[6], is_equal_to(5));
+ assert_that(items[7], is_equal_to(5));
+ assert_that(items[8], is_equal_to(5));
+ assert_that(items[9], is_equal_to(6));
+ assert_that(items[10], is_equal_to(9));
+}
+
+TestSuite *sort_tests() {
+ TestSuite *x = create_test_suite();
+ add_test(x, one_equals_one);
+
+ add_test(x, merge_sort_sorts_a_null_list);
+ add_test(x, merge_sort_sorts_an_empty_list);
+ add_test(x, merge_sort_sorts_a_list_with_one_item);
+ add_test(x, merge_sort_sorts_a_list_with_two_items);
+ add_test(x, merge_sort_sorts_three_unique_items);
+ add_test(x, merge_sort_sorts_many_items);
+
+ add_test(x, quick_sort_sorts_a_null_list);
+ add_test(x, quick_sort_sorts_an_empty_list);
+ add_test(x, quick_sort_sorts_a_list_with_one_item);
+ add_test(x, quick_sort_sorts_a_list_with_two_items);
+ add_test(x, quick_sort_sorts_three_unique_items);
+ add_test(x, quick_sort_sorts_many_items);
+ return x;
+}
Makefile
@@ -12,3 +12,4 @@ test :
fmt :
clang-format -i src/**/**/*.c
+ clang-format -i src/**/*.c