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 months ago
JSON representation
Stevan Apter-style trees in C++17
- Host: GitHub
- URL: https://github.com/tlack/atree
- Owner: tlack
- Created: 2017-02-18T02:36:43.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2023-12-17T11:12:31.000Z (almost 2 years ago)
- Last Synced: 2025-03-30T19:08:14.167Z (7 months ago)
- Topics: apl, data-structures, kdb, tree, vector
- Language: C++
- Size: 15.6 KB
- Stars: 370
- Watchers: 6
- Forks: 9
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
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++