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 \brief provides read-write access to the root node, and by
extension the rest of the tree. extension the rest of the tree.
todo: why wasn't this provided previously?
\return a reference to the root node of the tree. \return a reference to the root node of the tree.
*/ */
Node& root() { return m_nodes[0]; } 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). \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(); 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. \brief splits the node into subnodes.

View File

@ -31,94 +31,6 @@ class Orthtree;
namespace Orthtrees { 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 \ingroup PkgOrthtreeTraversal
\brief A class used for performing a preorder traversal. \brief A class used for performing a preorder traversal.
@ -147,11 +59,11 @@ public:
if (n->is_leaf()) { if (n->is_leaf()) {
auto next = next_sibling(m_orthtree, n); auto next = m_orthtree.next_sibling(n);
if (nullptr == next) { if (nullptr == next) {
return next_sibling_up(m_orthtree, n); return m_orthtree.next_sibling_up(n);
} }
return next; return next;
@ -221,15 +133,15 @@ public:
Leaves_traversal(const Tree& orthtree) : m_orthtree(orthtree) {} Leaves_traversal(const Tree& orthtree) : m_orthtree(orthtree) {}
const Node* first() const { 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 { 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) 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; return next;
} }
@ -262,21 +174,21 @@ public:
template <typename Node> template <typename Node>
const Node* first() const { 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> template <typename Node>
const Node* next(const Node* n) const { 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) { if (!next) {
const Node* up = n; const Node* up = n;
do { do {
up = next_sibling_up(m_orthtree, up); up = m_orthtree.next_sibling_up(up);
if (!up) if (!up)
return nullptr; return nullptr;
next = first_child_at_depth(m_orthtree, up, m_depth); next = m_orthtree.first_child_at_depth(up, m_depth);
} while (!next); } while (!next);
} }