This repository contains selected examples and solutions to exercises from Purely Functional Data Structures.
| instance | persistence | snoc | head | tail |
|---|---|---|---|---|
| Batched Queue | ephemeral | O(n) / O(1)* | O(1) | O(n) / O(1)* |
| Banker's Queue | persistent | O(n) / O(1)* | O(1) | O(n) / O(1)* |
| Physicist's Queue | persistent | O(n) / O(1)* | O(1) | O(n) / O(1)* |
| Real-Time Queue | persistent | O(1) | O(1) | O(1) |
| Hood-Melville Queue | persistent | O(1) | O(1) | O(1) |
| Bootstrapped Queue | persistent | O(log*(n))** | O(1) | O(log*(n))** |
| Implicit Queue | persistent | O(log(n)) / O(1)* | O(1) | O(log(n)) / O(1)* |
* amortized time
** amortized time, log*(n) is constant in practice
| instance | persistence | cons | head | tail | snoc |
|---|---|---|---|---|---|
| Output-Restricted Banker's Deque | persistent | O(n) / O(1)* | O(1) | O(n) / O(1)* | O(n) / O(1)* |
| Output-Restricted Real-Time Deque | persistent | O(1) | O(1) | O(1) | O(1) |
| Output-Restricted Hood-Melville Deque | persistent | O(1)** | O(1) | O(1) | O(1) |
| instance | persistence | cons | head | tail | snoc | last | init |
|---|---|---|---|---|---|---|---|
| Banker's Deque | persistent | O(n) / O(1)* | O(1) | O(n) / O(1)* | O(n) / O(1)* | O(1) | O(n) / O(1)* |
| Real-Time Deque | persistent | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) |
* amortized time
** via the ConsQueue wrapper
| instance | persistence | cons | snoc | ++ | head | tail |
|---|---|---|---|---|---|---|
| Catenable List | persistent | O(1)** | O(1)** | O(1)* | O(1) | O(n) / O(1)* |
* amortized time
** depends on the complexity of snoc of the underlying queue
| instance | persistence | cons | snoc | ++ | head | tail | last | init |
|---|---|---|---|---|---|---|---|---|
| Simple Catenable Deque | persistent | O(1)** | O(1)** | O(log(n))* | O(1) | O(1)* | O(1) | O(1)* |
| Implicit Catenable Deque | persistent | O(1)** | O(1)** | O(1)* | O(1) | O(1)* | O(1) | O(1)* |
* amortized time
** amortized or worst-case time (depends on the underlying deque instance)
| instance | cons | head | tail | lookup | update |
|---|---|---|---|---|---|
| Binary Random Access List | O(log(n)) | O(log(n)) / O(1)** | O(log(n)) | O(log(n)) | O(log(n)) |
| Alternative Binary Random Access List | O(log(n)) | O(log(n)) / O(1)** | O(log(n)) | O(log(n)) | O(log(n)) |
| Zeroless Binary Random Access List | O(log(n)) | O(1) | O(log(n)) | O(log(i)) | O(log(i)) |
| Zeroless Redundant Bin. Random Access List | O(log(n)) / O(1)* | O(1) | O(log(n)) / O(1)* | O(log(i)) | O(log(i)) |
| Skew Binary Random Access List | O(1) | O(1) | O(1) | O(min(i, log(n))) | O(min(i, log(n))) |
where n is the list size and i is the index parameter of the lookup/update.
* amortized time
** with explicit reference to the head element
| instance | persistence | insert | merge | findMin | deleteMin |
|---|---|---|---|---|---|
| Leftist Heap | ephemeral | O(log(n)) | O(log(n)) | O(1) | O(log(n)) |
| Binomial Heap | persistent | O(log(n)) / O(1)* | O(log(n)) | O(log(n)) / O(1)** | O(log(n)) |
| Scheduled Binomial Heap | persistent | O(1) | O(log(n)) | O(log(n)) / O(1)** | O(log(n)) |
| Skew Binomial Heap | persistent | O(1) | O(log(n)) | O(log(n)) / O(1)** | O(log(n)) |
| Splay Heap | ephemeral | O(n) / O(log(n))* | O(n) / O(log(n))* | O(n) / O(log(n))* / O(1)** | O(n) / O(log(n))* |
| Pairing Heap | ephemeral | O(1) | O(1) | O(1) | O(n) / O(log(n))* |
| Lazy Pairing Heap | persistent | O(1) | O(1)* | O(1) | O(log(n))* |
| Bootstrapped Heap | persistent | O(1)' | O(1)' | O(1) | O(log(n))' |
* amortized time
** with explicit reference to the minimum element
' either worst-case or amortized depending on the underlying heap
| instance | persistence | add | sort |
|---|---|---|---|
| Merge Sort | persistent | O(log(n))* | O(n)* |
| Scheduled Merge Sort | persistent | O(log(n)) | O(n) |
* amortized time
| instance | persistence | member | insert |
|---|---|---|---|
| Binary Search Tree | ephemeral | O(n) | O(n) |
| Red-Black Tree | ephemeral | O(log(n)) | O(log(n)) |
| instance | lookup | bind |
|---|---|---|
| Trie | O(qm) | O(qm) |
| Trie of Trees | O(qm) | O(qm) |
where
- O(q) is the query complexity (e.g. size of an aggregated key
[k]orTree k) - O(m) is the operation complexity of the underlying map
m k
See terminology for brief description and definition of concepts and techniques from the book that is used to describe data structure instances in the IHaskell notebooks.
Haskell code can be found in IHaskell
notebooks under the notebooks directory. In order to view and edit them
one can start a Docker container running Jupyter with IHaskell kernel via
make ihaskellor just make.
Note that this is a personal learning place that was created while reading the book. I do encourage others to buy and read it!