Skip to content

Commit

Permalink
add iterator to paring heap
Browse files Browse the repository at this point in the history
  • Loading branch information
jere8184 committed Jan 26, 2025
1 parent 865289b commit 6b485a4
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 9 deletions.
202 changes: 193 additions & 9 deletions libopenage/datastructure/pairing_heap.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2014-2025 the openage authors. See copying.md for legal info.
// Copyright 2014-2024 the openage authors. See copying.md for legal info.

#pragma once

Expand All @@ -17,6 +17,7 @@
*/

#include <functional>
#include <iterator>
#include <memory>
#include <type_traits>
#include <unordered_set>
Expand All @@ -36,13 +37,17 @@ template <typename T,
typename heapnode_t>
class PairingHeap;

template <typename T, typename compare>
class PairingHeapIterator;


template <typename T, typename compare = std::less<T>>
class PairingHeapNode {
public:
using this_type = PairingHeapNode<T, compare>;

friend PairingHeap<T, compare, this_type>;
friend PairingHeapIterator<T, compare>;

T data;
compare cmp;
Expand Down Expand Up @@ -186,6 +191,166 @@ class PairingHeapNode {
};


/**
* @brief Iterator class for PairingHeap.
*
* This class provides a bidirectional iterator for the PairingHeap data structure.
* It allows traversal of the heap in both forward and backward directions.
* It is depth-first traversal.
*
* @tparam T The type of elements stored in the heap.
* @tparam compare The comparison functor used to order the elements.
*/
template <typename T, typename compare = std::less<T>>
class PairingHeapIterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T *;
using reference = T &;

/**
* @brief Constructs an iterator starting at the given node.
*
* @param node The starting node for the iterator.
*/
PairingHeapIterator(PairingHeapNode<T, compare> *node) :
current(node) {}

/**
* @brief Dereference operator.
*
* @return A reference to the data stored in the current node.
*/
reference operator*() const {
return current->data;
}

/**
* @brief Member access operator.
*
* @return A pointer to the data stored in the current node.
*/
pointer operator->() const {
return &(current->data);
}


/**
* @brief Get current node.
*
* @return The current node.
*/
PairingHeapNode<T, compare> *node() {
return current;
}


/**
* @brief Pre-increment operator.
*
* Moves the iterator to the next node in the heap.
*
* @return A reference to the incremented iterator.
*/
PairingHeapIterator &operator++() {
if (current->first_child) {
current = current->first_child;
}
else if (current->next_sibling) {
current = current->next_sibling;
}
else {
while (current->parent && !current->parent->next_sibling) {
current = current->parent;
}
if (current->parent) {
current = current->parent->next_sibling;
}
else {
current = nullptr;
}
}
return *this;
}

/**
* @brief Post-increment operator.
*
* Moves the iterator to the next node in the heap.
*
* @return A copy of the iterator before incrementing.
*/
PairingHeapIterator operator++(int) {
PairingHeapIterator tmp = *this;
++(*this);
return tmp;
}

/**
* @brief Pre-decrement operator.
*
* Moves the iterator to the previous node in the heap.
*
* @return A reference to the decremented iterator.
*/
PairingHeapIterator &operator--() {
if (current->prev_sibling) {
current = current->prev_sibling;
while (current->first_child) {
current = current->first_child;
while (current->next_sibling) {
current = current->next_sibling;
}
}
}
else if (current->parent) {
current = current->parent;
}
return *this;
}

/**
* @brief Post-decrement operator.
*
* Moves the iterator to the previous node in the heap.
*
* @return A copy of the iterator before decrementing.
*/
PairingHeapIterator operator--(int) {
PairingHeapIterator tmp = *this;
--(*this);
return tmp;
}

/**
* @brief Equality comparison operator.
*
* @param a The first iterator to compare.
* @param b The second iterator to compare.
* @return True if both iterators point to the same node, false otherwise.
*/
friend bool operator==(const PairingHeapIterator &a, const PairingHeapIterator &b) {
return a.current == b.current;
}

/**
* @brief Inequality comparison operator.
*
* @param a The first iterator to compare.
* @param b The second iterator to compare.
* @return True if the iterators point to different nodes, false otherwise.
*/
friend bool operator!=(const PairingHeapIterator &a, const PairingHeapIterator &b) {
return a.current != b.current;
}

private:
PairingHeapNode<T, compare> *current; ///< Pointer to the current node in the heap.
};


/**
* (Quite) efficient heap implementation.
*/
Expand All @@ -196,6 +361,7 @@ class PairingHeap final {
public:
using element_t = heapnode_t *;
using this_type = PairingHeap<T, compare, heapnode_t>;
using iterator = PairingHeapIterator<T, compare>;

/**
* create a empty heap.
Expand Down Expand Up @@ -404,8 +570,15 @@ class PairingHeap final {
* erase all elements on the heap.
*/
void clear() {
auto delete_node = [](element_t& node) { delete node; node = nullptr; };
this->iter_all<true>(delete_node);
std::vector<element_t> nodes_vec;
nodes_vec.reserve(this->size());
for (iterator it = this->begin(); it != this->end(); it++) {
nodes_vec.push_back(it.node());
}
for (element_t node : nodes_vec) {
delete node;
}

this->root_node = nullptr;
this->node_count = 0;
#if OPENAGE_PAIRINGHEAP_DEBUG
Expand Down Expand Up @@ -586,10 +759,18 @@ class PairingHeap final {
* @param func Function to apply to each node.
*/
template <bool reverse = false>
void iter_all(const std::function<void(element_t &)> &func) {
void iter_all(const std::function<void(const element_t &)> &func) const {
this->walk_tree<reverse>(this->root_node, func);
}

iterator begin() const {
return iterator(this->root_node);
}

iterator end() const {
return iterator(nullptr);
}

private:
/**
* Apply the given function to all nodes in the tree.
Expand All @@ -599,18 +780,21 @@ class PairingHeap final {
* @param func Function to apply to each node.
*/
template <bool reverse = false>
void walk_tree(element_t &start,
const std::function<void(element_t &)> &func) {
void walk_tree(const element_t &start,
const std::function<void(const element_t &)> &func) const {
if constexpr (not reverse) {
func(start);
}

if (start) {
auto node = start->first_child;
while (node) {
while (true) {
if (not node) {
break;
}

this->walk_tree<reverse>(node, func);
if (node)
node = node->next_sibling;
node = node->next_sibling;
}
if constexpr (reverse) {
func(start);
Expand Down
11 changes: 11 additions & 0 deletions libopenage/datastructure/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ void pairing_heap_3() {
heap.push(heap_elem{3});
heap.push(heap_elem{4});
heap.push(heap_elem{5});


int i = 0;
int a[6] = {0,5,4,3,2,1};
for(auto elem : heap)
{
TESTEQUALS(elem.data, a[i]);
i++;
}


heap.pop(); // trigger pairing

heap.clear();
Expand Down

0 comments on commit 6b485a4

Please sign in to comment.