# AVLTree
Pure Elixir [AVL tree](https://en.wikipedia.org/wiki/AVL_tree) implementation.
This data structure is very similar to `MapSet`, but unlike the latter,
elements in the `AVLTree` are always sorted in ascending or descending order.
To sort items, `AVLTree` uses a comparison function that looks like:
`less(a, b) :: boolean`
This function returns `true` if element `a` must be placed strictly before element `b`, otherwise it returns false.
`AVLTree` can store duplicate elements.
It is important to understand that duplicate elements are not necessarily the same.
Values `a` and `b` are considered equal if they satisfy the following condition:
`less(a, b) == false and less(b, a) == false`, where `less(x, y)` is comparison function
For example, if the comparison function is `fn {a, _}, {b, _} -> a < b end`,
then the elements `{1, 10}` and `{1, 20}` are considered equal, although actually they aren't.
By default, comparison function is `Kernel.</2`.
## Features
- custom comparison function;
- support for duplicate elements;
- `Collectable`, `Enumerable`, `Inspect` protocols;
- drawing the tree in the console :)
## Basic Usage
By default, inserted elements are sorted in ascending order:
```elixir
iex> tree = AVLTree.new()
#AVLTree<[]>
iex> tree = AVLTree.put(tree, 5)
iex> tree = AVLTree.put(tree, 2)
iex> tree = [1, 3, 6, 4] |> Enum.into(tree)
iex> tree
#AVLTree<[1, 2, 3, 4, 5, 6]>
```
You can specify ordering when creating a tree:
```elixir
iex> tree1 = AVLTree.new(:asc)
iex> tree2 = AVLTree.new(:desc)
iex> [4, 2, 1, 3] |> Enum.into(tree1)
#AVLTree<[1, 2, 3, 4]>
iex> [4, 2, 1, 3] |> Enum.into(tree2)
#AVLTree<[4, 3, 2, 1]>
```
Also you can use a custom comparison function.
Example of a tree with tuples as elements, ordered by the first field
```elixir
iex> tree = AVLTree.new(fn {a, _}, {b, _} -> a < b end)
iex> [{2, "A"}, {3, "B"}, {1, "C"}] |> Enum.into(tree)
#AVLTree<[{1, "C"}, {2, "A"}, {3, "B"}]>
```
Checks if the tree contains a value
```elixir
iex> tree = [5, 2, 1, 3] |> Enum.into(AVLTree.new())
iex> AVLTree.member?(tree, 2)
true
```
`AVLTree` fully supports `Enumerable` protocol
```elixir
iex> tree = [4, 2, 1, 3] |> Enum.into(AVLTree.new())
iex> Enum.to_list(tree)
[1, 2, 3, 4]
iex> Enum.sum(tree)
10
```
## Sorted list of dates
Let's create an ascending list of `DateTime` values.
```elixir
iex> tree = AVLTree.new(fn a, b -> DateTime.compare(a, b) == :lt end)
iex> [
...> ~U[2020-02-03 01:01:01Z],
...> ~U[2020-01-01 01:01:01Z],
...> ~U[2019-10-10 02:11:01Z],
...> ~U[2020-01-01 01:01:02Z]
...> ] |> Enum.into(tree)
#AVLTree<[~U[2019-10-10 02:11:01Z], ~U[2020-01-01 01:01:01Z], ~U[2020-01-01 01:01:02Z], ~U[2020-02-03 01:01:01Z]]>
```
## AVLTree as a map.
If you use a key-value pairs as elements, `AVLTree` can work as a map:
Create a tree
```elixir
tree = AVLTree.new(fn {a, _}, {b, _} -> a < b end)
```
Insert key-value pairs:
```elixir
tree =
tree
|> AVLTree.put({:a, "first value"})
|> AVLTree.put({:c, "third value"})
|> AVLTree.put({:b, "second value"})
```
or
```elixir
tree =
[a: "first value", c: "third value", b: "second value"]
|> Enum.into(tree)
```
Retrieve element by key. We can use anything as a value since comparison function cares only about keys.
```elixir
AVLTree.get(tree, {:b, nil}) # {:b, "second value"}
```
Delete element:
```elixir
AVLTree.delete(tree, {:b, nil}) # #AVLTree<[a: "first value", c: "third value"]>
```
Benefits? Elements are always ordered by keys. Custom comparison function.
## Performance
All inserts, removes and searches in general has complexity of `Ο(lg(n))`.
This implementation is about 4-5 times slower than `MapSet`.
To run benchmark use:
```shell
mix run bench/run.exs
```