Add functions to get node indices & retrieve nodes by index

This commit is contained in:
JacksonCampolattaro 2023-03-29 22:46:52 +02:00
parent 6dec072b00
commit 14726a1e41
2 changed files with 101 additions and 99 deletions

View File

@ -436,12 +436,22 @@ public:
\brief provides read-write access to the root node, and by
extension the rest of the tree.
todo: why wasn't this provided previously?
\return a reference to the root node of the tree.
*/
Node& root() { return m_nodes[0]; }
std::size_t index(const Node& node) const {
return std::distance(m_nodes.data(), &node);
}
const Node& operator[](std::size_t index) const {
return m_nodes[index];
}
Node& operator[](std::size_t index) {
return m_nodes[index];
}
/*!
\brief returns the deepest level reached by a leaf node in this tree (root being level 0).
*/
@ -665,6 +675,86 @@ public:
return node.m_children.get();
}
const Node* next_sibling(const Node* n) const {
// todo: maybe this should take a reference?
if (nullptr == n)
return nullptr;
// If this node has no parent, it has no siblings
if (n->is_root())
return nullptr;
// Find out which child this is
std::size_t index = n->local_coordinates().to_ulong();
constexpr static int degree = Node::Degree::value;
// Return null if this is the last child
if (int(index) == degree - 1)
return nullptr;
// Otherwise, return the next child
return &(children(parent(*n))[index + 1]);
}
const Node* next_sibling_up(const Node* n) const {
if (!n || n->is_root()) return nullptr;
auto up = &parent(*n);
while (nullptr != up) {
if (nullptr != next_sibling(up))
return next_sibling(up);
// todo: this could be cleaned up; it's probably not necessary to involve pointers here
up = up->is_root() ? nullptr : &parent(*up);
}
return nullptr;
}
const Node* deepest_first_child(const Node* n) const {
if (n == nullptr)
return nullptr;
// Find the deepest child on the left
auto first = n;
while (!first->is_leaf())
first = &children(*first)[0];
return first;
}
const Node* first_child_at_depth(const Node* n, std::size_t depth) const {
if (!n)
return nullptr;
std::stack<const Node*> todo;
todo.push(n);
if (n->depth() == depth)
return n;
while (!todo.empty()) {
const Node* node = todo.top();
todo.pop();
if (node->depth() == depth)
return node;
if (!node->is_leaf())
for (int i = 0; i < Node::Degree::value; ++i)
todo.push(&((*node)[std::size_t(Node::Degree::value - 1 - i)]));
}
return nullptr;
}
/*!
\brief splits the node into subnodes.

View File

@ -31,94 +31,6 @@ class Orthtree;
namespace Orthtrees {
/// \cond SKIP_IN_MANUAL
// todo: all of these could be members of Orthtree
template <typename Tree>
const typename Tree::Node* next_sibling(const Tree& orthtree, const typename Tree::Node* n) {
// todo: maybe this should take a reference?
if (nullptr == n)
return nullptr;
// If this node has no parent, it has no siblings
if (n->is_root())
return nullptr;
// Find out which child this is
std::size_t index = n->local_coordinates().to_ulong();
constexpr static int degree = Tree::Node::Degree::value;
// Return null if this is the last child
if (int(index) == degree - 1)
return nullptr;
// Otherwise, return the next child
return &(orthtree.children(orthtree.parent(*n))[index + 1]);
}
template <typename Tree>
const typename Tree::Node* next_sibling_up(const Tree& orthtree, const typename Tree::Node* n) {
if (!n || n->is_root()) return nullptr;
auto up = &orthtree.parent(*n);
while (nullptr != up) {
if (nullptr != next_sibling(orthtree, up))
return next_sibling(orthtree, up);
// todo: this could be cleaned up; it's probably not necessary to involve pointers here
up = up->is_root() ? nullptr : &orthtree.parent(*up);
}
return nullptr;
}
template <typename Tree>
const typename Tree::Node* deepest_first_child(const Tree& orthtree, const typename Tree::Node* n) {
if (n == nullptr)
return nullptr;
// Find the deepest child on the left
auto first = n;
while (!first->is_leaf())
first = &orthtree.children(*first)[0];
return first;
}
template <typename Tree>
const typename Tree::Node* first_child_at_depth(const Tree& orthtree, const typename Tree::Node* n, std::size_t depth) {
if (!n)
return nullptr;
std::stack<const typename Tree::Node*> todo;
todo.push(n);
if (n->depth() == depth)
return n;
while (!todo.empty()) {
const typename Tree::Node* node = todo.top();
todo.pop();
if (node->depth() == depth)
return node;
if (!node->is_leaf())
for (int i = 0; i < Tree::Node::Degree::value; ++i)
todo.push(&((*node)[std::size_t(Tree::Node::Degree::value - 1 - i)]));
}
return nullptr;
}
/// \endcond
/*!
\ingroup PkgOrthtreeTraversal
\brief A class used for performing a preorder traversal.
@ -147,11 +59,11 @@ public:
if (n->is_leaf()) {
auto next = next_sibling(m_orthtree, n);
auto next = m_orthtree.next_sibling(n);
if (nullptr == next) {
return next_sibling_up(m_orthtree, n);
return m_orthtree.next_sibling_up(n);
}
return next;
@ -221,15 +133,15 @@ public:
Leaves_traversal(const Tree& orthtree) : m_orthtree(orthtree) {}
const Node* first() const {
return deepest_first_child(m_orthtree, &m_orthtree.root());
return m_orthtree.deepest_first_child(&m_orthtree.root());
}
const Node* next(const Node* n) const {
auto next = deepest_first_child(m_orthtree, next_sibling(m_orthtree, n));
auto next = m_orthtree.deepest_first_child(m_orthtree.next_sibling(n));
if (!next)
next = deepest_first_child(m_orthtree, next_sibling_up(m_orthtree, n));
next = m_orthtree.deepest_first_child(m_orthtree.next_sibling_up(n));
return next;
}
@ -262,21 +174,21 @@ public:
template <typename Node>
const Node* first() const {
return first_child_at_depth(m_orthtree, m_orthtree.root(), m_depth);
return m_orthtree.first_child_at_depth(m_orthtree.root(), m_depth);
}
template <typename Node>
const Node* next(const Node* n) const {
const Node* next = next_sibling(m_orthtree, n);
const Node* next = m_orthtree.next_sibling(n);
if (!next) {
const Node* up = n;
do {
up = next_sibling_up(m_orthtree, up);
up = m_orthtree.next_sibling_up(up);
if (!up)
return nullptr;
next = first_child_at_depth(m_orthtree, up, m_depth);
next = m_orthtree.first_child_at_depth(up, m_depth);
} while (!next);
}