Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/tlack/atree

Stevan Apter-style trees in C++17
https://github.com/tlack/atree

apl data-structures kdb tree vector

Last synced: 7 days ago
JSON representation

Stevan Apter-style trees in C++17

Awesome Lists containing this project

README

        

# Apter Trees in C++

Apter Trees are a simpler representation of trees using just two vectors: `[nodevalues,
parentindices]`.

This repo contains a tree-like data type implemented in C++17, in the style of Stevan Apter in
[Treetable: a case-study in q](http://archive.vector.org.uk/art10500340).

## Who cares?

A tree is a data structure in which values have parent-child relationships to
each other. They come in many forms.

In most software, trees are implemented like a typical binary tree, where each
node contains its own data and a pointer to each of its children, nominally just
left and right, which are also nodes. The cycle continues.

Using such a data structure can be challenging due to recursion and slow due to
cache behavior in modern systems and frequent malloc()s. The concept of who
"owns" a tree node in such a system can become complex in multi-layered
software.

Apter Trees are much faster, easier to reason about, and easier to implement.

## How it works

An Apter tree is implemented as two same-sized arrays.

One is a vector (array) of data (we'll call it `d`). These correspond to the
values, or things that each node contains.

The other is a vector of parent indices (`p`). The index of an item in the `d`
vector is used as its key, which we will call `c` in the examples below.

Often, the key/index `c` will just be an int.

So, if we had a dog family tree in which Coco was the father of Molly and Arca,
and Arca had a son named Cricket, you might have a data structure like:

```
tree.d = ["Coco", "Molly", "Arca","Cricket"]
tree.p = [0,0,0,2]
```

A node with a key of `0` whose parent is zero is the root node. Apter trees
require a root node, or the use of `-1` to mean "no parent", which is slightly
less elegant so I'll ignore it.

Computers are very, very fast at manipulating vectors. They're so much faster
than pointer operations that comparisons of big-O notation for an algorithm
don't play out in practice.

## Operations in psuedocode

The technique is applicable in all languages. This library is written in C++
but I will use psuedocode to explain how it works.

* Empty tree

```
tree() = { {d:[], p:[]} } # some sort of [data,parentidxs] vector
```

* Number of nodes

```
nodecnt(t) = { len(t.p) }
```

* Keys of all nodes

```
join(x,y) = { flatten(x,y) } # append to vec. i.e., x.push_back(y), x[]=y, etc.
range(x,y) = { # Q til, APL/C++ iota; return [x, x+1, x+2, ...y-1]
i=x; ret=[]; while(i++