|
datastructures 0.1.0
|
This header only library is going to hold all the various data structures I will implement in the future, for now it contains just maps and persistent maps implemented using AVL trees.
To use this library just copy the include/datastructures directory into your project, no external compilation is needed, the data structures live in the datastructures namespace.
For the documentation see this page, or if its down, generate the docs using:
The code can be found here.
FetchContent to automatically download Catch2)dot)** for class and hierarchy diagramsdoxygen-awesome-css theme via FetchContent)datastructuresdatastructures::detailtests directory and use catch2.The library so far defines:
This is an implementation of an associative container which maps values of one type to another. It has an O(log n) access and O(log n) insertion/deletion.
To map class is defined in the map.hpp header. It is mostly compatible with the map class from the standard template library, although lacks some features which didn't seem that important for me to implement, like .emplace() etc.
The map class also supports custom methods to compare keys. To use this feature, define a comparator class which has an overloaded operator()(key_type, key_type) method and pass it to the TKeyComp template parameter. If the comparator needs context, use the corresponding constructor to pass your instance to the class.
Similarly, custom allocators are also supported with the exact same logic. Use TAlloc to tell the map which allocator type to use and optionally pass the allocator instance to the constructor.
| Operation | Time complexity |
|---|---|
find | O(log n) |
contains | O(log n) |
insert | O(log n) |
insert_or_assign | O(log n) |
erase(key) | O(log n) |
operator[] | O(log n) |
at | O(log n) |
begin / end | O(log n) |
size / empty | O(1) |
clear | O(n) |
| iteration over all elements | O(n) |
A map that has immutable updates, which means that you can search in all older versions.
When you access some element you have to specify in which version to search in.
Similarly, when you perform updates, you can choose which version the new one will be based on. This will create a version tree with each version based on some older one.
The persistence is implemented using the path copying method. That means that for every update operation every modified node and the path to them are copied.
Since the path lenght is atmost log n, the time complexity does not change, although each new version requires O(log n) new space instead of the O(1) new space as in the ethereal map.
Each version has an ID associated with it. The structure does not remember what change each version brought, if you need this behaviour, implement it separately.
Each update method returns a boolean value encoding whether the opeartion succeded, in such case a new version was created. They also return the newest version ID in that branch, that means the original version ID in the case the operation was not performed and the newly created version ID if the operation was carried out successfuly. The only exception is insert_or_assign which always creates a new version and the boolean value carries the information about the type of the update method that was used.
Version IDs are assigned sequentially starting from 0. For every version with ID n, all versions with IDs from 0 to n - 1 also exist. Therefore, version IDs form a continuous sequence without gaps, and the most recently created version always has the highest ID.
The initial empty-tree version is a special case and has the ID -1.
To get the preceeding version for some other version with ID i, call map.get_preceding_version(i). To get the last version ID created use map.get_current_version(). With these two functions and the fact above you can build the whole version tree if needed.
If an invalid version ID (does not exist) is passed to an access method, the function will behave the same way as if the the key did not exist.
If the invalid version ID is given to an update method, the newly created version is going to be based on the initial version with ID -1.
This prints:
which represents the version tree:
| Operation | Time complexity | New Space |
|---|---|---|
find | O(log n) | 0 |
contains | O(log n) | 0 |
insert | O(log n) | O(log n) |
insert_or_assign | O(log n) | O(log n) |
erase(key) | O(log n) | O(log n) |
size / empty | O(1) | 0 |
clear | O(n) | 0 |
The project is licenced under GNU public licence.