Skip to content

Commit

Permalink
Optimizations and added Compare option
Browse files Browse the repository at this point in the history
  • Loading branch information
Gabriele A. Ron committed Aug 23, 2022
1 parent aabdbc2 commit a07b6a8
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 49 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ if (NOT CMAKE_CXX_FLAGS)
if (NOT ${SANITIZE} STREQUAL "OFF")
target_compile_options(${PROJECT_NAME} INTERFACE -fsanitize=${SANITIZE})
target_compile_options(${PROJECT_NAME} INTERFACE -g)
target_link_options(${PROJECT_NAME} INTERFACE -fsanitize=${SANITIZE})
endif ()

if (CMAKE_BUILD_TYPE STREQUAL "Debug")
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ The API for the Fibonacci Heap is quite simple:
However, once the heap is ordered, this runs in constant time as well.

* `Node pop_minimum()`
* Pops off the _minimum node and returns the entire node
* Pops off the _top node and returns the entire node
* Makes a call to `get_minimum`, so the same distinctions apply

* `void alter_key(T key, T new_key)`
Expand Down
2 changes: 1 addition & 1 deletion benchmark/app/int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class priority_queue_mfh : public FibonacciHeap<T> {
public:

priority_queue_mfh() = default;
priority_queue_mfh(size_t n) : FibonacciHeap<T>(n) {}
explicit priority_queue_mfh(size_t n) : FibonacciHeap<T>(n) {}

[[nodiscard]] typename FibonacciHeap<T>::Node& top() {
return *this->get_minimum();
Expand Down
4 changes: 2 additions & 2 deletions benchmark/app/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

#define run_inf CppBenchmark::Settings().Infinite().Attempts(50)
#define N 10000000
#define RATIO 65536
#define RATIO 32768

namespace GRon {
template<typename T>
class priority_queue_mfh : public FibonacciHeap<T> {
public:

priority_queue_mfh() = default;
priority_queue_mfh(size_t n) : FibonacciHeap<T>(n) {}
explicit priority_queue_mfh(size_t n) : FibonacciHeap<T>(n) {}

[[nodiscard]] typename FibonacciHeap<T>::Node& top() {
return *this->get_minimum();
Expand Down
14 changes: 8 additions & 6 deletions include/GRon/FibonacciHeap/FibonacciHeap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
#include <ostream>

namespace GRon {
template<std::three_way_comparable T, template<typename...> class Container = std::list>
template<std::three_way_comparable T,
template<typename...> class Container = std::list,
template<typename...> class Compare = std::less>
class FibonacciHeap {
public:
struct Node {
Expand All @@ -34,9 +36,9 @@ namespace GRon {

virtual ~Node() = default;

[[nodiscard]] size_t degree() const;
[[nodiscard]] inline size_t degree() const;

[[nodiscard]] size_t size() const;
[[nodiscard]] inline size_t size() const;

bool operator==(const Node& obj) const;

Expand All @@ -51,7 +53,7 @@ namespace GRon {

FibonacciHeap() = default;

explicit FibonacciHeap(size_t reserve) : _size(0), _clean(false), _minimum(nullptr), _nodes(reserve),
explicit FibonacciHeap(size_t reserve) : _size(0), _clean(false), _top(nullptr), _nodes(reserve),
_removed(), root_list() {};

FibonacciHeap(const FibonacciHeap&) = default;
Expand All @@ -64,7 +66,7 @@ namespace GRon {

virtual ~FibonacciHeap() = default;

[[nodiscard]] size_t size() const;
[[nodiscard]] inline size_t size() const;

void insert(const T &key);

Expand All @@ -78,7 +80,7 @@ namespace GRon {
protected:
size_t _size{0};
bool _clean{false};
Node* _minimum{nullptr};
Node* _top{nullptr};
Container<Node> _nodes;
Container<Node*> _removed;

Expand Down
82 changes: 43 additions & 39 deletions include/GRon/FibonacciHeap/template/FibonacciHeap.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
#include <vector>

/// Node
template<std::three_way_comparable T, template<typename...> class Container>
size_t GRon::FibonacciHeap<T, Container>::Node::degree() const {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
size_t GRon::FibonacciHeap<T, Container, Compare>::Node::degree() const {
return children.size();
}

template<std::three_way_comparable T, template<typename...> class Container>
size_t GRon::FibonacciHeap<T, Container>::Node::size() const {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
size_t GRon::FibonacciHeap<T, Container, Compare>::Node::size() const {
size_t ret = 1;

for (auto& i : children) {
Expand All @@ -22,34 +22,34 @@ size_t GRon::FibonacciHeap<T, Container>::Node::size() const {
return ret;
}

template<std::three_way_comparable T, template<typename...> class Container>
bool GRon::FibonacciHeap<T, Container>::Node::operator==(const FibonacciHeap::Node& obj) const {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
bool GRon::FibonacciHeap<T, Container, Compare>::Node::operator==(const FibonacciHeap::Node& obj) const {
return key == obj.key;
}

template<std::three_way_comparable T, template<typename...> class Container>
bool GRon::FibonacciHeap<T, Container>::Node::operator==(const T& obj) const {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
bool GRon::FibonacciHeap<T, Container, Compare>::Node::operator==(const T& obj) const {
return key == obj;
}

template<std::three_way_comparable T, template<typename...> class Container>
std::weak_ordering GRon::FibonacciHeap<T, Container>::Node::operator<=>(Node& obj) const {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
std::weak_ordering GRon::FibonacciHeap<T, Container, Compare>::Node::operator<=>(Node& obj) const {
return key <=> obj.key;
}

template<std::three_way_comparable T, template<typename...> class Container>
std::weak_ordering GRon::FibonacciHeap<T, Container>::Node::operator<=>(T& obj) const {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
std::weak_ordering GRon::FibonacciHeap<T, Container, Compare>::Node::operator<=>(T& obj) const {
return key <=> obj;
}

/// Fibonacci Heap
template<std::three_way_comparable T, template<typename...> class Container>
size_t GRon::FibonacciHeap<T, Container>::size() const {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
size_t GRon::FibonacciHeap<T, Container, Compare>::size() const {
return _size;
}

template<std::three_way_comparable T, template<typename...> class Container>
void GRon::FibonacciHeap<T, Container>::insert(const T& key) {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
void GRon::FibonacciHeap<T, Container, Compare>::insert(const T& key) {
_clean = true;
_size++;

Expand All @@ -63,11 +63,9 @@ void GRon::FibonacciHeap<T, Container>::insert(const T& key) {
_removed.pop_back();
}

template<std::three_way_comparable T, template<typename...> class Container>
typename GRon::FibonacciHeap<T, Container>::Node* GRon::FibonacciHeap<T, Container>::get_minimum() {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
typename GRon::FibonacciHeap<T, Container, Compare>::Node* GRon::FibonacciHeap<T, Container, Compare>::get_minimum() {
if (_clean) {


std::optional<size_t> max_degree = std::nullopt;

max_degree = std::log2f((double) size()) * 1.618;
Expand All @@ -78,19 +76,21 @@ typename GRon::FibonacciHeap<T, Container>::Node* GRon::FibonacciHeap<T, Contain

Node* current{nullptr};
Node* node{nullptr};
Compare<T> compare{};
auto start = degree_list.begin();
for (Node* root : root_list) {
if (!root) continue;

size_t degree = root->degree();
current = *std::next(degree_list.begin(), degree);
current = *std::next(start, degree);
if (!current) {
*std::next(degree_list.begin(), degree) = root;
*std::next(start, degree) = root;
continue;
}

node = root;
while (current) {
if (node->key < current->key) {
if (compare(node->key.value(), current->key.value())) {
current->parent = node;
node->children.push_back(current);
} else {
Expand All @@ -99,32 +99,36 @@ typename GRon::FibonacciHeap<T, Container>::Node* GRon::FibonacciHeap<T, Contain
node = current;
}

*std::next(degree_list.begin(), degree) = nullptr;
*std::next(start, degree) = nullptr;

if (degree + 1 >= degree_list.size()) break;

degree = node->degree();
current = *std::next(degree_list.begin(), degree);
current = *std::next(start, degree);
}

*std::next(degree_list.begin(), degree) = node;
*std::next(start, degree) = node;
}

/// This can be moved into the main loop above to improve efficiency for easily compared types,
/// but the partial specialization necessary is impossible, and making a base class has proven to be very very
/// frustrating.
_top = nullptr;
root_list.swap(degree_list);
for (auto& i : root_list) {
if (i && (!_minimum || i->key <= _minimum->key)) {
_minimum = i;
if (i && (!_top || compare(i->key.value(), _top->key.value()))) {
_top = i;
}
}

_clean = false;
}

return _minimum;
return _top;
}

template<std::three_way_comparable T, template<typename...> class Container>
std::optional<typename GRon::FibonacciHeap<T, Container>::Node> GRon::FibonacciHeap<T, Container>::pop_minimum() & {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
std::optional<typename GRon::FibonacciHeap<T, Container, Compare>::Node> GRon::FibonacciHeap<T, Container, Compare>::pop_minimum() & {
const Node* min = get_minimum();

if (!min) return std::nullopt;
Expand All @@ -138,15 +142,15 @@ std::optional<typename GRon::FibonacciHeap<T, Container>::Node> GRon::FibonacciH

_removed.push_back(&(*std::find(_nodes.begin(), _nodes.end(), *min)));

_minimum = nullptr;
_top = nullptr;
_clean = true;
_size--;

return *min;
}

template<std::three_way_comparable T, template<typename...> class Container>
std::optional<typename GRon::FibonacciHeap<T, Container>::Node> GRon::FibonacciHeap<T, Container>::pop_minimum() && {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
std::optional<typename GRon::FibonacciHeap<T, Container, Compare>::Node> GRon::FibonacciHeap<T, Container, Compare>::pop_minimum() && {
const Node* min = get_minimum();

if (!min) return std::nullopt;
Expand All @@ -160,15 +164,15 @@ std::optional<typename GRon::FibonacciHeap<T, Container>::Node> GRon::FibonacciH

_removed.push_back(&(*std::find(_nodes.begin(), _nodes.end(), *min)));

_minimum = nullptr;
_top = nullptr;
_clean = true;
_size--;

return std::move(*min);
}

template<std::three_way_comparable T, template<typename...> class Container>
void GRon::FibonacciHeap<T, Container>::cut_key(FibonacciHeap::Node* node, const T& key) {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
void GRon::FibonacciHeap<T, Container, Compare>::cut_key(FibonacciHeap::Node* node, const T& key) {
if (!node) return;

_clean = true;
Expand All @@ -191,8 +195,8 @@ void GRon::FibonacciHeap<T, Container>::cut_key(FibonacciHeap::Node* node, const
}
}

template<std::three_way_comparable T, template<typename...> class Container>
void GRon::FibonacciHeap<T, Container>::alter_key(const T& key, const T& new_key) {
template<std::three_way_comparable T, template<typename...> class Container, template<typename...> class Compare>
void GRon::FibonacciHeap<T, Container, Compare>::alter_key(const T& key, const T& new_key) {
auto old = std::find(_nodes.begin(), _nodes.end(), key);
if (old == _nodes.end()) return;

Expand Down

0 comments on commit a07b6a8

Please sign in to comment.