sashaafm / exads

Algorithms and Data Structures collection in Elixir
83 stars 12 forks source link

ALV tree #24

Open remshams opened 7 years ago

remshams commented 7 years ago

AVL Tree

As discussed the separate PR for the AVL Tree implementation/suggestion. I've made some changes to BST tree implementation as well as added the AVL tree which "sits" on top of the BST. Since the changes in the BST affect its general structure I'd love to to get some feedback.
The follwing gives a high level description about the changes. I think the details are best discussed at the specific code lines...

As mentioned please regard the current implementation as suggestion/MVP and basis for further improvements/extensions

General

As already hinted at in the intro the AVL tree leverages the already existing BST (which in my opinion kind of makes sense since lots of operation can be reused).
For the AVL tree to work some changes were required in the BST:

  1. Struct for BST nodes
  2. Comparable protocol for complex node values
  3. Hooks for the new, insert and delete operation

BST Node

The bst nodes consist of:

The idea regaring the augmentation is/was somehow related to the general procedure for augmenting datastructures (as for example described in CLRS Chapter 14 3rd edition).

Comparable protocol

For the BST to work with any kind of data structure as value (e.g. structs as well as "simple" types a BST Comparable protocol was introduced that the value types stored in the BST are required to implement (as described in this google discussion there doesn't seem to be a "generic" comparable protocol which can be implemented).
The BST already contains an implementation/fallback for the Any type (falling back to Kernel).

Hook methods

To avoid traversing the complete tree again for adding the AVL augmentations (balance factor and height) some kind of hooks were required to directly perform these calculations during BST new, insert and delete.
These have been named processors and currently the BST supports a pre- and post processor.

For the pre- as well as the postprocessor a standard identity processor is executed in case nothing is provided.

I made some thoughts whether to use a dedicated module or function keyword list. I decided for the latter as it somehow seems to be the elixir approach (but as I'm kind of new to elixir I could also be mistaken regaring that).

AVL Tree

The AVL tree implementation leverages the described BST extensions for performing the required operations.

Augmentation

It introduces an augmentation struct:

Postprocessor

A postprocess is added which performs the required rotations as well as node augmentations.

After every rotation the augmentation values are "updated". The summarized steps are:

  1. Perform the standard BST operation (like insert or delete)
  2. For all nodes on the path to the node (implicitly done by the BST operation)
    1. Check if the node is balanced
    2. Rotate if required
    3. Augment

Although in the case of insert it would be sufficient to just check the parant of the newly inserted node, the immutable character of elixir/erlang required all nodes on the path from the root to the affected node to be traversed.

Tests

Tests for the BST updates as well as the AVL tree operations have been added.
The test dedicated to the AVL tree should cover the different rotation cases (please let me know in case I've missed cases).

Other

I had some trouble to get the dialyzer going through. It seems that it has issues with structs as well as protocols. Therefore a dialyzer.ignore-warnings file has been added to get a green build again ;). I'd love to hear if someone knows how to avoid these warnings.
I've found a elixir talk regarding that issue and it looks like this is somehow a bug. However the talk is from 2014 so maybe there have been some changes regarding that.
Also worth mentioning is that I do not get the issue on my local machine, it just appears during the travis build.

The displayed credo issue is just a warning regarding the @spec definition for the greater- and less implementations for the Comparable protocol.

In case I have missed anything else please let me know ;)