A heap is a binary tree **stored in an array** in which all levels but the lowest are filled. It is guaranteed that the parent of index $i$ is greater than or equal to the element at index $i$.
- the parent of index $i$ is stored at $i/2$
- the left child of index $i$ is stored at $2i$
- the right child of index $i$ is stored at $2i+1$
Quicksort operates by selecting a **pivot point** that ensures that everything to the left of the pivot is less than anything to the right of the pivot, which is what partitioning does.
Sorting calls partitioning with smaller and smaller bounds until the collection is sorted.
```rust
fn sort(a: Vec, left: usize, right: usize) {
if left <right{
let pivot = partition(A, left, right);
sort(A, left, pivot);
sort(A, pivot+1, right);
}
}
```
- In the best case, if partitioning is even, the time complexity is $T(n)=T(n/2)+\Theta(n)=\Theta(n\log n)$.
- In the worst case, if one side only has one element, which occurs if the list is sorted, the time complexity is $\Theta(n^2)$.
### Counting sort
If items are or are linked to a number from $1..n$ (duplicates are allowed), counting sort counts the number of each number, then moves things to the correct position. Where $k$ is the size of the counter array, the time complexity is $O(n+k)$.
First, construct a count prefix sum array:
```rust
fn count(A: Vec, K: usize) {
let counter = vec![0; K];
for i in A {
counter[i] += 1;
}
for (index, val) in counter.iter_mut().enumerate() {
- A **cut** $(S, V-S)$ is a partition of vertices into disjoint sets $S$ and $V-S$.
- An edge $u,v\in E$ **crosses the cut** $(S,V-S)$ if t`he endpoints are on different sides of the cut.
- A cut **respects** a set of edges $A$ if and only if no edge in $A$ crosses the cut.
- A **light edge** is the minimum of all edges that could cross the cut. There can be more than one light edge per cut.
A **spanning tree** of $G$ is a subgraph that contains all of its vertices. An MST minimises the sum of all edges in the spanning tree.
To create an MST:
1. Add edges from the spanning tree to an empty set, maintaining that the set is always a subset of an MST (only "safe edges" are added)
The **Prim-Jarnik algorithm** grows a tree one vertex at a time. $A$ is a subset of the already computed portion of $T$, and all vertices outside $A$ have a weight of infinity if there is no edge.
```rust
// r is the start vertex
fn create_mst_prim(G: Graph, r: Vertex) {
// clean all vertices
for vertex in G.vertices.iter_mut() {
vertex.min_weight = INFINITY;
vertex.parent = None;
}
let Q = BinaryHeap::from(G.vertices); // priority queue
while let Some(u) = Q.pop() {
for v in u.adjacent_vertices.iter_mut() {
if Q.contains(v) && v.edge_to(u).weight <v.min_weight{
v.min_weight = v.edge_to(u).weight;
Q."modify_key"(v);
v.parent = u;
}
}
}
}
```
**Kruskal's algorithm** is objectively better by relying on edges instead.