this about halves the time spent on level_order_it and drastically reduces the time spent in children_it
342 lines
7.0 KiB
Plaintext
342 lines
7.0 KiB
Plaintext
module mtree{Type};
|
|
|
|
import std::core::mem;
|
|
import std::core::mem::allocator;
|
|
import std::io;
|
|
import std::bits;
|
|
import std::collections::list;
|
|
|
|
|
|
alias Bitmap = ulong;
|
|
const BITS = Bitmap.sizeof*8;
|
|
|
|
alias IdxList = list::List{int};
|
|
|
|
// more: if positive it contains the index of the next node that contains the children information
|
|
struct Node {
|
|
int more;
|
|
int parent;
|
|
Bitmap children;
|
|
}
|
|
|
|
struct MTree {
|
|
usz elements;
|
|
Allocator allocator;
|
|
IdxList queue;
|
|
Bitmap[] used;
|
|
Type[] elem_mat; // element matrix
|
|
Node[] refs_mat; // relationship matrix
|
|
}
|
|
|
|
|
|
fn void MTree.init(&tree, usz size, Allocator allocator = mem)
|
|
{
|
|
// round size to the nearest multiple of BITS
|
|
size = size + size%BITS;
|
|
|
|
tree.elements = 0;
|
|
tree.allocator = allocator;
|
|
tree.queue.init(allocator, size);
|
|
tree.used = allocator::new_array(tree.allocator, Bitmap, size/BITS);
|
|
tree.elem_mat = allocator::new_array(tree.allocator, Type, size);
|
|
tree.refs_mat = allocator::new_array(tree.allocator, Node, size);
|
|
|
|
foreach (&r: tree.refs_mat) {
|
|
r.more = -1;
|
|
}
|
|
}
|
|
|
|
|
|
fn void MTree.free(&tree)
|
|
{
|
|
tree.elements = 0;
|
|
tree.queue.free();
|
|
(void)allocator::free(tree.allocator, tree.used);
|
|
(void)allocator::free(tree.allocator, tree.elem_mat);
|
|
(void)allocator::free(tree.allocator, tree.refs_mat);
|
|
}
|
|
|
|
|
|
fn int MTree.get_free_spot(&tree)
|
|
{
|
|
foreach (idx, d: tree.used) {
|
|
if (d != $typeof(d).max) {
|
|
int spot = (int)idx*BITS + BITS-(int)d.clz();
|
|
return spot;
|
|
}
|
|
}
|
|
unreachable("no free spots left");
|
|
}
|
|
|
|
<* @require idx >= 0 *>
|
|
fn void MTree.set_used(&tree, int idx)
|
|
{
|
|
int r = idx % BITS;
|
|
int q = idx / BITS;
|
|
tree.used[q] |= (1l << r);
|
|
}
|
|
|
|
<* @require idx >= 0 *>
|
|
fn void MTree.unset_used(&tree, int idx)
|
|
{
|
|
int r = idx % BITS;
|
|
int q = idx / BITS;
|
|
tree.used[q] &= ~(1l << r);
|
|
}
|
|
|
|
<* @require idx >= 0 *>
|
|
fn bool MTree.is_used(&tree, int idx)
|
|
{
|
|
int r = idx % BITS;
|
|
int q = idx / BITS;
|
|
return !!(tree.used[q] & (1l << r));
|
|
}
|
|
|
|
|
|
// get the last node in the "more" chain
|
|
<* @require tree.is_used(parent) == true *>
|
|
fn int MTree.last_node(&tree, int parent)
|
|
{
|
|
while(tree.refs_mat[parent].more >= 0) {
|
|
parent = tree.refs_mat[parent].more;
|
|
}
|
|
return parent;
|
|
}
|
|
|
|
|
|
<* @require tree.elements == 0 || tree.is_used(parent) == true *>
|
|
fn int MTree.add(&tree, int parent, Type t)
|
|
{
|
|
int idx = tree.get_free_spot();
|
|
int subtree = idx / BITS;
|
|
|
|
tree.set_used(idx);
|
|
tree.elem_mat[idx] = t;
|
|
tree.refs_mat[idx] = (Node){
|
|
.parent = parent,
|
|
.more = -1,
|
|
};
|
|
|
|
tree.elements++;
|
|
// root element, has no parent
|
|
if (tree.elements == 1) {
|
|
tree.refs_mat[idx].parent = -1;
|
|
return idx;
|
|
}
|
|
|
|
|
|
// if the parent already has a node in the same subtree as the child then update that node's
|
|
// children bitmap
|
|
bool done;
|
|
for (int p = parent; p >= 0; p = tree.refs_mat[p].more) {
|
|
int ps = p/BITS;
|
|
if (ps == subtree) {
|
|
tree.refs_mat[p].children |= (1l << (idx%BITS));
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
// on fail we need to create another parent node
|
|
if (!done) {
|
|
int new_more = tree.get_free_spot();
|
|
// if the new node does not land in the same subtree as the child we cannot do
|
|
// anything since the references are immutable
|
|
if (new_more/BITS != subtree) {
|
|
unreachable("cannot allocate new child for parent");
|
|
}
|
|
tree.set_used(new_more);
|
|
tree.elements++;
|
|
// update the "more" chain
|
|
int last_link = tree.last_node(parent);
|
|
tree.refs_mat[last_link].more = new_more;
|
|
tree.refs_mat[new_more].more = -1;
|
|
tree.refs_mat[new_more].children |= (long)(1 << (idx%BITS));
|
|
tree.refs_mat[new_more].parent = last_link;
|
|
// FIXME: the elem_mat is not updated, do we need to?
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
|
|
// get the index of the n-th children of parent, -1 otherwise
|
|
// usage: for (int i, c; (c = tree.children_it(parent, i)) >= 0; i++) { ... }
|
|
fn int MTree.children_it(&tree, int parent, int n)
|
|
{
|
|
int tot_children;
|
|
int child;
|
|
for (int p = parent; p >= 0; p = tree.refs_mat[p].more) {
|
|
int cn = (int)tree.refs_mat[p].children.popcount();
|
|
tot_children += cn;
|
|
|
|
// we are in the right subtree
|
|
if (tot_children > n) {
|
|
child = (p/BITS) * BITS; // start at the parent's subtree index
|
|
int j = cn - (tot_children - n); // we need the j-th children of this node
|
|
Bitmap u = tree.refs_mat[p].children;
|
|
|
|
child += j; // add the children number
|
|
do {
|
|
child += (int)u.ctz(); // increment by the skipped zeroes
|
|
u >>= u.ctz() + 1;
|
|
j--;
|
|
} while (j >= 0);
|
|
|
|
return child;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
fn int MTree.children_num(&tree, int parent)
|
|
{
|
|
int n;
|
|
for (int p = parent; p >= 0; p = tree.refs_mat[p].more) {
|
|
n += (int)tree.refs_mat[p].children.popcount();
|
|
}
|
|
return n;
|
|
}
|
|
|
|
fn int MTree.subtree_size(&tree, int parent)
|
|
{
|
|
int x = tree.children_num(parent);
|
|
int c;
|
|
for (int n; (c = tree.children_it(parent, n)) >= 0; n++) {
|
|
x += tree.subtree_size(c);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
|
|
fn int MTree.level_order_it(&tree, int parent, int i)
|
|
{
|
|
if (i == 0) {
|
|
tree.queue.clear();
|
|
tree.queue.push(parent);
|
|
}
|
|
|
|
if (tree.queue.len() == 0) return -1;
|
|
|
|
int p = tree.queue.pop_first()!!;
|
|
int c;
|
|
for (int n; (c = tree.children_it(p, n)) >= 0; n++) {
|
|
tree.queue.push(c);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
fn void MTree.prune(&tree, int parent)
|
|
{
|
|
int c;
|
|
for (int i = 0; (c = tree.children_it(parent, i)) >= 0; i++) {
|
|
tree.prune(c); // prune the subtree
|
|
|
|
// delete all children including their more chain
|
|
for (int p = c; p >= 0;) {
|
|
int next = tree.refs_mat[p].more;
|
|
tree.unset_used(p);
|
|
tree.refs_mat[p] = {.more = -1};
|
|
p = next;
|
|
}
|
|
|
|
}
|
|
|
|
// finally delete the parent
|
|
for (int p = parent; p >= 0;) {
|
|
int next = tree.refs_mat[p].more;
|
|
tree.unset_used(p);
|
|
tree.elements--;
|
|
tree.refs_mat[p] = {.more = -1};
|
|
p = next;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
macro bool MTree.is_root(&t, int i) => t.refs_mat[i].parent == -1;
|
|
|
|
fn void MTree.print(&tree)
|
|
{
|
|
foreach (idx, c: tree.elem_mat) {
|
|
if (tree.is_used((int)idx)) {
|
|
io::printfn("[%d](%s) parent:%d more:%d children:%b",
|
|
idx, c, tree.refs_mat[idx].parent, tree.refs_mat[idx].more,
|
|
tree.refs_mat[idx].children
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
module foo;
|
|
|
|
import std::io;
|
|
import mtree;
|
|
|
|
alias Tree = mtree::MTree{int};
|
|
|
|
fn int main()
|
|
{
|
|
Tree t;
|
|
t.init(256);
|
|
defer t.free();
|
|
/*
|
|
int root = t.add(0, 0);
|
|
int c1 = t.add(root, 1);
|
|
int c2 = t.add(root, 2);
|
|
|
|
int c11 = t.add(c1, 11);
|
|
int c12 = t.add(c1, 12);
|
|
|
|
int c3 = t.add(root, 3);
|
|
|
|
for (int x = 0; x < 70; x++) {
|
|
t.add(c2, x);
|
|
}
|
|
|
|
int c31 = t.add(c3, 31);
|
|
int c32 = t.add(c3, 32);
|
|
|
|
int c4 = t.add(root, 4);
|
|
|
|
int c13 = t.add(c1, 13);
|
|
int c14 = t.add(c1, 14);
|
|
int c15 = t.add(c1, 15);
|
|
|
|
t.prune(c2);
|
|
|
|
io::printn("printing tree");
|
|
t.print();
|
|
|
|
usz x;
|
|
foreach_r (u: t.used) {
|
|
x += u.popcount();
|
|
io::printf("%b ", u);
|
|
}
|
|
io::printfn("TOT:%d/%d",x,t.elements);
|
|
|
|
io::printn(t.subtree_size(root));
|
|
|
|
io::printn();
|
|
*/
|
|
|
|
int root = t.add(0, 0);
|
|
int c1 = t.add(root, 1);
|
|
int c2 = t.add(root, 2);
|
|
int c3 = t.add(root, 3);
|
|
|
|
int c11 = t.add(c1, 11);
|
|
int c12 = t.add(c1, 12);
|
|
|
|
int c111 = t.add(c11, 111);
|
|
int c121 = t.add(c12, 121);
|
|
|
|
int c31 = t.add(c3, 31);
|
|
|
|
int c;
|
|
for (int i; (c = t.level_order_it(root, i)) >= 0; i++) {
|
|
io::printfn("%d-th: [%d](%d)", i, c, t.elem_mat[c]);
|
|
}
|
|
|
|
return 0;
|
|
} |