From 5da56c92146fe55220b026de9247d712c15f564f Mon Sep 17 00:00:00 2001 From: RunFMe Date: Fri, 23 Nov 2018 00:02:06 +0500 Subject: [PATCH 1/5] initial commit --- CMakeLists.txt | 26 +++ README.md | 3 +- cmake/googletest-download.cmake | 20 ++ cmake/googletest.cmake | 32 +++ src/FibbonachiHeap/CMakeLists.txt | 15 ++ src/FibbonachiHeap/FibbonachiHeap.hpp | 325 ++++++++++++++++++++++++++ test/CMakeLists.txt | 19 ++ test/fibbonachi_heap_test.cpp | 184 +++++++++++++++ test/main.cpp | 11 + 9 files changed, 634 insertions(+), 1 deletion(-) create mode 100644 CMakeLists.txt create mode 100644 cmake/googletest-download.cmake create mode 100644 cmake/googletest.cmake create mode 100644 src/FibbonachiHeap/CMakeLists.txt create mode 100644 src/FibbonachiHeap/FibbonachiHeap.hpp create mode 100644 test/CMakeLists.txt create mode 100644 test/fibbonachi_heap_test.cpp create mode 100644 test/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..db23fb1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +project(heaps CXX) +set(CMAKE_CXX_STANDARD 17) + +include(GNUInstallDirs) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}) + +# we use this to get code coverage +if(CMAKE_CXX_COMPILER_ID MATCHES GNU) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") +endif() + +add_subdirectory(src/FibbonachiHeap) + +include(cmake/googletest.cmake) +fetch_googletest( + ${PROJECT_SOURCE_DIR}/cmake + ${PROJECT_BINARY_DIR}/googletest +) + +enable_testing() +add_subdirectory(test) + diff --git a/README.md b/README.md index 1292fe6..227710c 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -# heapsLab \ No newline at end of file +# gtest-example-linkedlist +Example of usage of Google Test library. Made as a part of course Algorithms and Data Structures at DIHT MIPT. diff --git a/cmake/googletest-download.cmake b/cmake/googletest-download.cmake new file mode 100644 index 0000000..f580295 --- /dev/null +++ b/cmake/googletest-download.cmake @@ -0,0 +1,20 @@ +# code copied from https://crascit.com/2015/07/25/cmake-gtest/ +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +project(googletest-download NONE) + +include(ExternalProject) + +ExternalProject_Add( + googletest + SOURCE_DIR "@GOOGLETEST_DOWNLOAD_ROOT@/googletest-src" + BINARY_DIR "@GOOGLETEST_DOWNLOAD_ROOT@/googletest-build" + GIT_REPOSITORY + https://github.com/google/googletest.git + GIT_TAG + release-1.8.0 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) diff --git a/cmake/googletest.cmake b/cmake/googletest.cmake new file mode 100644 index 0000000..de0c3bb --- /dev/null +++ b/cmake/googletest.cmake @@ -0,0 +1,32 @@ +# the following code to fetch googletest +# is inspired by and adapted after https://crascit.com/2015/07/25/cmake-gtest/ +# download and unpack googletest at configure time + +macro(fetch_googletest _download_module_path _download_root) + set(GOOGLETEST_DOWNLOAD_ROOT ${_download_root}) + configure_file( + ${_download_module_path}/googletest-download.cmake + ${_download_root}/CMakeLists.txt + @ONLY + ) + unset(GOOGLETEST_DOWNLOAD_ROOT) + + execute_process( + COMMAND + "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" . + WORKING_DIRECTORY + ${_download_root} + ) + execute_process( + COMMAND + "${CMAKE_COMMAND}" --build . + WORKING_DIRECTORY + ${_download_root} + ) + + # adds the targers: gtest, gtest_main, gmock, gmock_main + add_subdirectory( + ${_download_root}/googletest-src + ${_download_root}/googletest-build + ) +endmacro() diff --git a/src/FibbonachiHeap/CMakeLists.txt b/src/FibbonachiHeap/CMakeLists.txt new file mode 100644 index 0000000..52f56e9 --- /dev/null +++ b/src/FibbonachiHeap/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(fibbonachiHeap) + +target_sources( + fibbonachiHeap + PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/FibbonachiHeap.hpp +) + +target_include_directories( + fibbonachiHeap + PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + +set_target_properties(fibbonachiHeap PROPERTIES LINKER_LANGUAGE CXX) \ No newline at end of file diff --git a/src/FibbonachiHeap/FibbonachiHeap.hpp b/src/FibbonachiHeap/FibbonachiHeap.hpp new file mode 100644 index 0000000..3142996 --- /dev/null +++ b/src/FibbonachiHeap/FibbonachiHeap.hpp @@ -0,0 +1,325 @@ +// +// Created by runfme on 13.11.18. +// + +#include +#include +#include +template +class FibbonachiHeap { + private: + class TreeNode; + class Pointer; + + public: + FibbonachiHeap() { + size_ = 0; + min_root = nullptr; + } + + bool empty() { + return size_ == 0; + } + + unsigned long size() { + return size_; + } + + std::shared_ptr insert(T value) { + auto new_root = new TreeNode(value); + concat_node_lists(min_root, new_root); + ++size_; + + if (new_root->value < min_root->value) { + min_root = new_root; + } + + return new_root->get_pointer(); + } + + T min() { + return min_root->value; + } + + T extract_min() { + assert(!empty()); + auto extracted_node = min_root; + extract_node(min_root); + --size_; + + if (min_root != nullptr){ + consolidate(); + } + find_new_min(); + + T return_value = extracted_node->value; + extracted_node->get_pointer()->valid = false; + delete extracted_node; + + return return_value; + } + + void remove(std::shared_ptr pointer) { + assert(pointer->is_valid()); + auto node = pointer->node; + auto parent = node->parent; + + extract_node(node); + --size_; + cascading_cut(parent); + find_new_min(); + + pointer->valid = false; + delete node; + } + + void change(std::shared_ptr pointer, T new_value) { + assert(new_value <= pointer->value()); + + auto node = pointer->node; + auto parent = node->parent; + + cut_out_node(node); + + node->value = new_value; + concat_node_lists(min_root, node); + + cascading_cut(parent); + find_new_min(); + } + + void merge(FibbonachiHeap &heap) { + if (heap.min_root != nullptr) { + concat_node_lists(min_root, heap.min_root); + size_ += heap.size_; + find_new_min(); + + heap.min_root = nullptr; + heap.size_ = 0; + } + } + + ~FibbonachiHeap() { + recursive_delete(min_root); + } + + private: + unsigned long size_; + TreeNode* min_root; + + void static concat_node_lists(TreeNode* &first_list, TreeNode* second_list) { + assert(second_list != nullptr); + + if (first_list == nullptr) { + first_list = second_list; + } else { + first_list->left_sib->right_sib = second_list; + second_list->left_sib->right_sib = first_list; + + std::swap(first_list->left_sib, second_list->left_sib); + } + } + + void cut_out_node(TreeNode* node) { + auto parent = node->parent; + if (node->parent != nullptr) { + node->parent = nullptr; + } + + if (node->left_sib == node) { + if (parent == nullptr) { + min_root = nullptr; + } else { + parent->child = nullptr; + } + } else { + if (parent != nullptr){ + parent->child = node->right_sib; + } else if (node == min_root){ + min_root= node->right_sib; + } + + node->left_sib->right_sib = node->right_sib; + node->right_sib->left_sib = node->left_sib; + + node->left_sib = node->right_sib = node; + } + } + + unsigned long D() { + unsigned long highest_bit = 0; + while ((size_ >> highest_bit) > 0) { + ++highest_bit; + } + + return highest_bit; + } + + void consolidate() { + assert(min_root != nullptr); + + unsigned long highest_bit = D(); + TreeNode* roots[highest_bit]; + for (unsigned long i = 0; i < highest_bit; ++i) { + roots[i] = nullptr; + } + + while (min_root != nullptr) { + auto cur_root = min_root; + cut_out_node(min_root); + + while (roots[cur_root->get_degree()] != nullptr) { + auto second_root = roots[cur_root->get_degree()]; + roots[cur_root->get_degree()] = nullptr; + + cur_root = cur_root->hang(second_root); + } + roots[cur_root->get_degree()] = cur_root; + } + + for (unsigned long j = 0; j < highest_bit; ++j) { + if (roots[j] != nullptr) { + concat_node_lists(min_root, roots[j]); + if (roots[j]->value < min_root->value) { + min_root = roots[j]; + } + } + } + } + + void add_children_as_roots(TreeNode* node) { + if (node->child != nullptr) { + auto cur_child = node->child; + do { + cur_child->parent = nullptr; + cur_child->mark = false; + cur_child = cur_child->right_sib; + } while (cur_child != node->child); + + concat_node_lists(min_root, node->child); + node->child = nullptr; + } + } + + void find_new_min() { + if (min_root != nullptr) { + auto cur_root = min_root; + auto new_min = cur_root; + + do { + if (cur_root->value < new_min->value) { + new_min = cur_root; + } + cur_root = cur_root->right_sib; + } while (cur_root != min_root); + + min_root = new_min; + } + } + + void extract_node(TreeNode* node) { + cut_out_node(node); + add_children_as_roots(node); + } + + void recursive_delete(TreeNode* node) { + if (node == nullptr) { + return; + } + recursive_delete(node->child); + node->left_sib->right_sib = nullptr; + recursive_delete(node->right_sib); + + delete node; + } + + void cascading_cut(TreeNode* node) { + if (node == nullptr || node->parent == nullptr) { + return; + } + + if (node->mark) { + auto parent = node->parent; + + cut_out_node(node); + node->mark = false; + concat_node_lists(min_root, node); + + cascading_cut(parent); + } else { + node->mark = true; + } + } + + class TreeNode { + public: + T value; + bool mark; + TreeNode* left_sib; + TreeNode* right_sib; + TreeNode* parent; + TreeNode* child; + + explicit TreeNode(T value) { + this->value = value; + degree = 0; + mark = false; + pointer = std::shared_ptr(new Pointer(this)); + + left_sib = right_sib = this; + parent = nullptr; + child = nullptr; + } + + TreeNode* hang(TreeNode* second_tree) { + assert(degree == second_tree->degree); + + TreeNode* root_tree = this; + if (second_tree->value < root_tree->value) { + std::swap(root_tree, second_tree); + } + + concat_node_lists(root_tree->child, second_tree); + second_tree->parent = root_tree; + + return root_tree; + } + + std::shared_ptr get_pointer() { + return pointer; + } + + unsigned long get_degree() { + return degree; + } + + private: + friend class FibbonachiHeap; + unsigned long degree; + std::shared_ptr pointer; + }; + + class Pointer { + friend class FibbonachiHeap; + public: + explicit Pointer(TreeNode* node) { + this->node = node; + this->valid = true; + } + + bool is_valid() { + return valid; + } + + T value() { + assert(is_valid()); + return node->value; + } + private: + TreeNode* node; + bool valid; + }; + +}; + + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..d88b837 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.9) + +add_executable( + unit_tests + fibbonachi_heap_test.cpp + main.cpp) + +target_link_libraries( + unit_tests + gtest_main + fibbonachiHeap +) + +add_test( + NAME + unit + COMMAND + ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}/unit_tests +) diff --git a/test/fibbonachi_heap_test.cpp b/test/fibbonachi_heap_test.cpp new file mode 100644 index 0000000..20e7035 --- /dev/null +++ b/test/fibbonachi_heap_test.cpp @@ -0,0 +1,184 @@ +// +// Created by runfme on 16.11.18. +// + + +#define BOOST_TEST_MAIN +#define BOOST_TEST_MODULE testFibbonachiHeap + +#include "../src/FibbonachiHeap/FibbonachiHeap.hpp" +#include +#include + +TEST(FibbonachiHeapBasics, Constructor) { + FibbonachiHeap heap = FibbonachiHeap(); + EXPECT_EQ(heap.empty(), true); +} + +TEST(FibbonachiHeapBasics, Empty) { + FibbonachiHeap heap = FibbonachiHeap(); + EXPECT_EQ(heap.empty(), true); + + heap.insert(1); + EXPECT_EQ(heap.empty(), false); +} + +TEST(FibbonachiHeapBasics, Insert) { + FibbonachiHeap heap = FibbonachiHeap(); + auto pointer = heap.insert(1); + EXPECT_EQ(pointer->value(), 1); +} + +TEST(FibbonachiHeapBasics, GetMin) { + FibbonachiHeap heap = FibbonachiHeap(); + auto pointer = heap.insert(1); + heap.insert(2); + heap.insert(5); + heap.insert(0); + heap.insert(3); + EXPECT_EQ(heap.min(), 0); +} + +TEST(FibbonachiHeapBasics, ExtractMin) { + FibbonachiHeap heap = FibbonachiHeap(); + heap.insert(2); + heap.insert(3); + heap.insert(5); + heap.insert(10); + heap.insert(3); + heap.insert(11); + EXPECT_EQ(heap.extract_min(), 2); + EXPECT_EQ(heap.extract_min(), 3); + EXPECT_EQ(heap.extract_min(), 3); + heap.insert(1); + EXPECT_EQ(heap.extract_min(), 1); + EXPECT_EQ(heap.extract_min(), 5); + EXPECT_EQ(heap.extract_min(), 10); + EXPECT_EQ(heap.extract_min(), 11); + + EXPECT_EQ(heap.size(), 0); +} + +TEST(FibbonachiHeapBasics, Size) { + FibbonachiHeap heap = FibbonachiHeap(); + EXPECT_EQ(heap.size(), 0); + heap.insert(1); + EXPECT_EQ(heap.size(), 1); + heap.insert(2); + heap.insert(6); + heap.insert(1); + EXPECT_EQ(heap.size(), 4); + heap.extract_min(); + heap.extract_min(); + EXPECT_EQ(heap.size(), 2); +} + +TEST(FibbonachiHeapBasics, Delete) { + FibbonachiHeap heap = FibbonachiHeap(); + auto pointer_to_1 = heap.insert(1); + heap.remove(pointer_to_1); + EXPECT_EQ(pointer_to_1->is_valid(), false); + EXPECT_EQ(heap.size(), 0); + + heap.insert(3); + auto pointer_to_0 = heap.insert(0); + heap.insert(1); + heap.remove(pointer_to_0); + EXPECT_EQ(pointer_to_0->is_valid(), false); + EXPECT_EQ(heap.min(), 1); +} + +TEST(FibbonachiHeapAdvanced, Change) { + FibbonachiHeap heap = FibbonachiHeap(); + heap.insert(1); + heap.insert(3); + auto pointer_to_2 = heap.insert(2); + heap.insert(1); + + heap.change(pointer_to_2, 0); + EXPECT_EQ(pointer_to_2->value(), 0); + EXPECT_EQ(heap.min(), 0); + + heap.change(pointer_to_2, -1); + EXPECT_EQ(pointer_to_2->value(), -1); + EXPECT_EQ(heap.min(), -1); +} +// +TEST(FibbonachiHeapAdvanced, MergeEmptyToNonEmpty) { + FibbonachiHeap heap1 = FibbonachiHeap(); + FibbonachiHeap heap2 = FibbonachiHeap(); + heap1.insert(1); + heap1.insert(3); + + heap1.merge(heap2); + EXPECT_EQ(heap1.min(), 1); + EXPECT_EQ(heap1.size(), 2); + EXPECT_EQ(heap2.size(), 0); +} + +TEST(FibbonachiHeapAdvanced, MergeNonEmptyToEmpty) { + FibbonachiHeap heap1 = FibbonachiHeap(); + FibbonachiHeap heap2 = FibbonachiHeap(); + heap1.insert(1); + heap1.insert(3); + + heap2.merge(heap1); + EXPECT_EQ(heap2.min(), 1); + EXPECT_EQ(heap2.size(), 2); + EXPECT_EQ(heap1.size(), 0); +} + +TEST(FibbonachiHeapAdvanced, MergeNonEmptyToNonEmpty) { + FibbonachiHeap heap1 = FibbonachiHeap(); + FibbonachiHeap heap2 = FibbonachiHeap(); + heap1.insert(1); + heap1.insert(3); + + heap2.insert(0); + heap2.insert(4); + + heap1.merge(heap2); + EXPECT_EQ(heap1.min(), 0); + EXPECT_EQ(heap1.size(), 4); + EXPECT_EQ(heap2.size(), 0); +} + +//TEST(FibbonachiHeapExceptions, RequestsToEmptyHeap) { +// FibbonachiHeap heap = FibbonachiHeap(); +// +// EXPECT_THROW(heap.min(), std::runtime_error); +// EXPECT_THROW(heap.extract_min(), std::runtime_error); +//} +// +//TEST(FibbonachiHeapExceptions, RequestsToInvalidatedPointer) { +// FibbonachiHeap heap = FibbonachiHeap(); +// auto pointer_to_1 = heap.insert(1); +// heap.remove(pointer_to_1); +// +// EXPECT_THROW(heap.remove(pointer_to_1), std::runtime_error); +// EXPECT_THROW(heap.change(pointer_to_1, 10), std::runtime_error); +//} + +TEST(FibbonachiHeapExceptions, Stress) { + std::priority_queue h; + FibbonachiHeap heap = FibbonachiHeap(); + for (int i = 0; i < 1; ++i) { + for (int j = 0; j < 500; ++j) { + int v = rand(); + int dec = 0+10000; + + auto a = heap.insert(v+dec); + h.push(-(v)); + + EXPECT_EQ(heap.size(), h.size()); + heap.change(a, v); + EXPECT_EQ(a->value(), v); +// heap.change(a, rand()); + } + for (int k = 0; k < 200; ++k) { + EXPECT_EQ(heap.extract_min(), -h.top()); + h.pop(); + EXPECT_EQ(heap.size(), h.size()); + } + } +} diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 0000000..5b08882 --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,11 @@ +// +// Created by sashka on 19.10.18. +// + +#include "gtest/gtest.h" + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 8b06fa8896b8d4ba33ba1bfdc8e2140c1f046558 Mon Sep 17 00:00:00 2001 From: RunFMe Date: Fri, 23 Nov 2018 00:17:14 +0500 Subject: [PATCH 2/5] add exceptions --- src/FibbonachiHeap/FibbonachiHeap.hpp | 59 ++++++++++++++++++--------- test/fibbonachi_heap_test.cpp | 55 +++++++------------------ 2 files changed, 55 insertions(+), 59 deletions(-) diff --git a/src/FibbonachiHeap/FibbonachiHeap.hpp b/src/FibbonachiHeap/FibbonachiHeap.hpp index 3142996..349bdb2 100644 --- a/src/FibbonachiHeap/FibbonachiHeap.hpp +++ b/src/FibbonachiHeap/FibbonachiHeap.hpp @@ -38,11 +38,18 @@ class FibbonachiHeap { } T min() { + if (empty()) { + throw std::runtime_error ("Heap is empty"); + } + return min_root->value; } T extract_min() { - assert(!empty()); + if (empty()) { + throw std::runtime_error ("Heap is empty"); + } + auto extracted_node = min_root; extract_node(min_root); --size_; @@ -60,7 +67,9 @@ class FibbonachiHeap { } void remove(std::shared_ptr pointer) { - assert(pointer->is_valid()); + if (!pointer->is_valid()) { + throw std::runtime_error ("Invalidated pointer to an element"); + } auto node = pointer->node; auto parent = node->parent; @@ -73,14 +82,18 @@ class FibbonachiHeap { delete node; } - void change(std::shared_ptr pointer, T new_value) { - assert(new_value <= pointer->value()); + void decrease_key(std::shared_ptr pointer, T new_value) { + if (!pointer->is_valid()) { + throw std::runtime_error ("Invalidated pointer to an element"); + } + if (new_value > pointer->value()) { + throw std::invalid_argument ("Value can only be decreased"); + } auto node = pointer->node; auto parent = node->parent; cut_out_node(node); - node->value = new_value; concat_node_lists(min_root, node); @@ -108,7 +121,9 @@ class FibbonachiHeap { TreeNode* min_root; void static concat_node_lists(TreeNode* &first_list, TreeNode* second_list) { - assert(second_list != nullptr); + if (second_list == nullptr) { + throw std::invalid_argument ("Can not append empty list"); + } if (first_list == nullptr) { first_list = second_list; @@ -156,7 +171,9 @@ class FibbonachiHeap { } void consolidate() { - assert(min_root != nullptr); + if (min_root == nullptr) { + throw std::runtime_error ("Can not consolidate empty heap"); + } unsigned long highest_bit = D(); TreeNode* roots[highest_bit]; @@ -168,13 +185,13 @@ class FibbonachiHeap { auto cur_root = min_root; cut_out_node(min_root); - while (roots[cur_root->get_degree()] != nullptr) { - auto second_root = roots[cur_root->get_degree()]; - roots[cur_root->get_degree()] = nullptr; + while (roots[cur_root->degree] != nullptr) { + auto second_root = roots[cur_root->degree]; + roots[cur_root->degree] = nullptr; cur_root = cur_root->hang(second_root); } - roots[cur_root->get_degree()] = cur_root; + roots[cur_root->degree] = cur_root; } for (unsigned long j = 0; j < highest_bit; ++j) { @@ -234,9 +251,12 @@ class FibbonachiHeap { } void cascading_cut(TreeNode* node) { - if (node == nullptr || node->parent == nullptr) { + if (node == nullptr) { return; } + if (node->parent == nullptr) { + node->degree -= 1; + } if (node->mark) { auto parent = node->parent; @@ -248,6 +268,7 @@ class FibbonachiHeap { cascading_cut(parent); } else { node->mark = true; + node->degree -= 1; } } @@ -259,6 +280,7 @@ class FibbonachiHeap { TreeNode* right_sib; TreeNode* parent; TreeNode* child; + unsigned long degree; explicit TreeNode(T value) { this->value = value; @@ -272,7 +294,9 @@ class FibbonachiHeap { } TreeNode* hang(TreeNode* second_tree) { - assert(degree == second_tree->degree); + if (degree != second_tree->degree) { + throw std::runtime_error ("Trees should have the same degree to hang one to another"); + } TreeNode* root_tree = this; if (second_tree->value < root_tree->value) { @@ -289,13 +313,8 @@ class FibbonachiHeap { return pointer; } - unsigned long get_degree() { - return degree; - } - private: friend class FibbonachiHeap; - unsigned long degree; std::shared_ptr pointer; }; @@ -312,7 +331,9 @@ class FibbonachiHeap { } T value() { - assert(is_valid()); + if (!is_valid()) { + throw std::runtime_error ("Invalidated pointer to an element"); + } return node->value; } private: diff --git a/test/fibbonachi_heap_test.cpp b/test/fibbonachi_heap_test.cpp index 20e7035..e081067 100644 --- a/test/fibbonachi_heap_test.cpp +++ b/test/fibbonachi_heap_test.cpp @@ -8,7 +8,6 @@ #include "../src/FibbonachiHeap/FibbonachiHeap.hpp" #include -#include TEST(FibbonachiHeapBasics, Constructor) { FibbonachiHeap heap = FibbonachiHeap(); @@ -95,15 +94,15 @@ TEST(FibbonachiHeapAdvanced, Change) { auto pointer_to_2 = heap.insert(2); heap.insert(1); - heap.change(pointer_to_2, 0); + heap.decrease_key(pointer_to_2, 0); EXPECT_EQ(pointer_to_2->value(), 0); EXPECT_EQ(heap.min(), 0); - heap.change(pointer_to_2, -1); + heap.decrease_key(pointer_to_2, -1); EXPECT_EQ(pointer_to_2->value(), -1); EXPECT_EQ(heap.min(), -1); } -// + TEST(FibbonachiHeapAdvanced, MergeEmptyToNonEmpty) { FibbonachiHeap heap1 = FibbonachiHeap(); FibbonachiHeap heap2 = FibbonachiHeap(); @@ -143,42 +142,18 @@ TEST(FibbonachiHeapAdvanced, MergeNonEmptyToNonEmpty) { EXPECT_EQ(heap2.size(), 0); } -//TEST(FibbonachiHeapExceptions, RequestsToEmptyHeap) { -// FibbonachiHeap heap = FibbonachiHeap(); -// -// EXPECT_THROW(heap.min(), std::runtime_error); -// EXPECT_THROW(heap.extract_min(), std::runtime_error); -//} -// -//TEST(FibbonachiHeapExceptions, RequestsToInvalidatedPointer) { -// FibbonachiHeap heap = FibbonachiHeap(); -// auto pointer_to_1 = heap.insert(1); -// heap.remove(pointer_to_1); -// -// EXPECT_THROW(heap.remove(pointer_to_1), std::runtime_error); -// EXPECT_THROW(heap.change(pointer_to_1, 10), std::runtime_error); -//} +TEST(FibbonachiHeapExceptions, RequestsToEmptyHeap) { + FibbonachiHeap heap = FibbonachiHeap(); -TEST(FibbonachiHeapExceptions, Stress) { - std::priority_queue h; + EXPECT_THROW(heap.min(), std::runtime_error); + EXPECT_THROW(heap.extract_min(), std::runtime_error); +} + +TEST(FibbonachiHeapExceptions, RequestsToInvalidatedPointer) { FibbonachiHeap heap = FibbonachiHeap(); - for (int i = 0; i < 1; ++i) { - for (int j = 0; j < 500; ++j) { - int v = rand(); - int dec = 0+10000; - - auto a = heap.insert(v+dec); - h.push(-(v)); - - EXPECT_EQ(heap.size(), h.size()); - heap.change(a, v); - EXPECT_EQ(a->value(), v); -// heap.change(a, rand()); - } - for (int k = 0; k < 200; ++k) { - EXPECT_EQ(heap.extract_min(), -h.top()); - h.pop(); - EXPECT_EQ(heap.size(), h.size()); - } - } + auto pointer_to_1 = heap.insert(1); + heap.remove(pointer_to_1); + + EXPECT_THROW(heap.remove(pointer_to_1), std::runtime_error); + EXPECT_THROW(heap.decrease_key(pointer_to_1, 10), std::runtime_error); } From e5e0e1bbee0e5799215b3aba8c704c68b3a76edf Mon Sep 17 00:00:00 2001 From: RunFMe Date: Sun, 3 Feb 2019 14:06:00 +0500 Subject: [PATCH 3/5] change test --- test/fibbonachi_heap_test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/fibbonachi_heap_test.cpp b/test/fibbonachi_heap_test.cpp index e081067..9dcca12 100644 --- a/test/fibbonachi_heap_test.cpp +++ b/test/fibbonachi_heap_test.cpp @@ -2,7 +2,6 @@ // Created by runfme on 16.11.18. // - #define BOOST_TEST_MAIN #define BOOST_TEST_MODULE testFibbonachiHeap @@ -156,4 +155,4 @@ TEST(FibbonachiHeapExceptions, RequestsToInvalidatedPointer) { EXPECT_THROW(heap.remove(pointer_to_1), std::runtime_error); EXPECT_THROW(heap.decrease_key(pointer_to_1, 10), std::runtime_error); -} +} \ No newline at end of file From fe7bf790d437969ed3d121945b6756d09bb70078 Mon Sep 17 00:00:00 2001 From: RunFMe Date: Sun, 3 Feb 2019 15:26:00 +0500 Subject: [PATCH 4/5] Swapped to shred_ptr --- src/{FibbonachiHeap => FibonacciHeap}/CMakeLists.txt | 0 .../FibbonachiHeap.hpp => FibonacciHeap/FibonacciHeap.hpp} | 0 test/{fibbonachi_heap_test.cpp => fibonacci_heap_test.cpp} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/{FibbonachiHeap => FibonacciHeap}/CMakeLists.txt (100%) rename src/{FibbonachiHeap/FibbonachiHeap.hpp => FibonacciHeap/FibonacciHeap.hpp} (100%) rename test/{fibbonachi_heap_test.cpp => fibonacci_heap_test.cpp} (100%) diff --git a/src/FibbonachiHeap/CMakeLists.txt b/src/FibonacciHeap/CMakeLists.txt similarity index 100% rename from src/FibbonachiHeap/CMakeLists.txt rename to src/FibonacciHeap/CMakeLists.txt diff --git a/src/FibbonachiHeap/FibbonachiHeap.hpp b/src/FibonacciHeap/FibonacciHeap.hpp similarity index 100% rename from src/FibbonachiHeap/FibbonachiHeap.hpp rename to src/FibonacciHeap/FibonacciHeap.hpp diff --git a/test/fibbonachi_heap_test.cpp b/test/fibonacci_heap_test.cpp similarity index 100% rename from test/fibbonachi_heap_test.cpp rename to test/fibonacci_heap_test.cpp From 3ae49f7686669a0534dfd450cc7b821f0f8a7530 Mon Sep 17 00:00:00 2001 From: RunFMe Date: Sun, 3 Feb 2019 15:27:15 +0500 Subject: [PATCH 5/5] Fix shared_ptr seg fault --- CMakeLists.txt | 2 +- src/FibonacciHeap/CMakeLists.txt | 10 +-- src/FibonacciHeap/FibonacciHeap.hpp | 122 ++++++++++++++-------------- test/CMakeLists.txt | 4 +- test/fibonacci_heap_test.cpp | 62 +++++++------- 5 files changed, 102 insertions(+), 98 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db23fb1..d1ce1c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES GNU) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") endif() -add_subdirectory(src/FibbonachiHeap) +add_subdirectory(src/FibonacciHeap) include(cmake/googletest.cmake) fetch_googletest( diff --git a/src/FibonacciHeap/CMakeLists.txt b/src/FibonacciHeap/CMakeLists.txt index 52f56e9..54e9cd9 100644 --- a/src/FibonacciHeap/CMakeLists.txt +++ b/src/FibonacciHeap/CMakeLists.txt @@ -1,15 +1,15 @@ -add_library(fibbonachiHeap) +add_library(fibonacciHeap) target_sources( - fibbonachiHeap + fibonacciHeap PUBLIC - ${CMAKE_CURRENT_LIST_DIR}/FibbonachiHeap.hpp + ${CMAKE_CURRENT_LIST_DIR}/FibonacciHeap.hpp ) target_include_directories( - fibbonachiHeap + fibonacciHeap PUBLIC ${CMAKE_CURRENT_LIST_DIR} ) -set_target_properties(fibbonachiHeap PROPERTIES LINKER_LANGUAGE CXX) \ No newline at end of file +set_target_properties(fibonacciHeap PROPERTIES LINKER_LANGUAGE CXX) \ No newline at end of file diff --git a/src/FibonacciHeap/FibonacciHeap.hpp b/src/FibonacciHeap/FibonacciHeap.hpp index 349bdb2..b8a69ee 100644 --- a/src/FibonacciHeap/FibonacciHeap.hpp +++ b/src/FibonacciHeap/FibonacciHeap.hpp @@ -5,14 +5,15 @@ #include #include #include -template -class FibbonachiHeap { + +template +class FibonacciHeap { private: class TreeNode; class Pointer; public: - FibbonachiHeap() { + FibonacciHeap() { size_ = 0; min_root = nullptr; } @@ -26,8 +27,8 @@ class FibbonachiHeap { } std::shared_ptr insert(T value) { - auto new_root = new TreeNode(value); - concat_node_lists(min_root, new_root); + auto new_root = TreeNode::create_node(value); + concatenate_node_lists(min_root, new_root); ++size_; if (new_root->value < min_root->value) { @@ -39,7 +40,7 @@ class FibbonachiHeap { T min() { if (empty()) { - throw std::runtime_error ("Heap is empty"); + throw std::runtime_error("Heap is empty"); } return min_root->value; @@ -47,28 +48,27 @@ class FibbonachiHeap { T extract_min() { if (empty()) { - throw std::runtime_error ("Heap is empty"); + throw std::runtime_error("Heap is empty"); } auto extracted_node = min_root; extract_node(min_root); --size_; - if (min_root != nullptr){ + if (min_root != nullptr) { consolidate(); } find_new_min(); T return_value = extracted_node->value; extracted_node->get_pointer()->valid = false; - delete extracted_node; return return_value; } void remove(std::shared_ptr pointer) { if (!pointer->is_valid()) { - throw std::runtime_error ("Invalidated pointer to an element"); + throw std::runtime_error("Invalidated pointer to an element"); } auto node = pointer->node; auto parent = node->parent; @@ -79,15 +79,14 @@ class FibbonachiHeap { find_new_min(); pointer->valid = false; - delete node; } void decrease_key(std::shared_ptr pointer, T new_value) { if (!pointer->is_valid()) { - throw std::runtime_error ("Invalidated pointer to an element"); + throw std::runtime_error("Invalidated pointer to an element"); } if (new_value > pointer->value()) { - throw std::invalid_argument ("Value can only be decreased"); + throw std::invalid_argument("Value can only be decreased"); } auto node = pointer->node; @@ -95,15 +94,15 @@ class FibbonachiHeap { cut_out_node(node); node->value = new_value; - concat_node_lists(min_root, node); + concatenate_node_lists(min_root, node); cascading_cut(parent); find_new_min(); } - void merge(FibbonachiHeap &heap) { + void merge(FibonacciHeap &heap) { if (heap.min_root != nullptr) { - concat_node_lists(min_root, heap.min_root); + concatenate_node_lists(min_root, heap.min_root); size_ += heap.size_; find_new_min(); @@ -112,17 +111,17 @@ class FibbonachiHeap { } } - ~FibbonachiHeap() { + ~FibonacciHeap() { recursive_delete(min_root); } private: unsigned long size_; - TreeNode* min_root; + std::shared_ptr min_root; - void static concat_node_lists(TreeNode* &first_list, TreeNode* second_list) { + void static concatenate_node_lists(std::shared_ptr &first_list, std::shared_ptr second_list) { if (second_list == nullptr) { - throw std::invalid_argument ("Can not append empty list"); + throw std::invalid_argument("Can not append empty list"); } if (first_list == nullptr) { @@ -135,7 +134,7 @@ class FibbonachiHeap { } } - void cut_out_node(TreeNode* node) { + void cut_out_node(std::shared_ptr node) { auto parent = node->parent; if (node->parent != nullptr) { node->parent = nullptr; @@ -143,15 +142,15 @@ class FibbonachiHeap { if (node->left_sib == node) { if (parent == nullptr) { - min_root = nullptr; + min_root = nullptr; } else { parent->child = nullptr; } } else { - if (parent != nullptr){ + if (parent != nullptr) { parent->child = node->right_sib; - } else if (node == min_root){ - min_root= node->right_sib; + } else if (node == min_root) { + min_root = node->right_sib; } node->left_sib->right_sib = node->right_sib; @@ -161,7 +160,7 @@ class FibbonachiHeap { } } - unsigned long D() { + unsigned long max_tree_degree() { unsigned long highest_bit = 0; while ((size_ >> highest_bit) > 0) { ++highest_bit; @@ -172,11 +171,11 @@ class FibbonachiHeap { void consolidate() { if (min_root == nullptr) { - throw std::runtime_error ("Can not consolidate empty heap"); + throw std::runtime_error("Can not consolidate empty heap"); } - unsigned long highest_bit = D(); - TreeNode* roots[highest_bit]; + unsigned long highest_bit = max_tree_degree(); + std::shared_ptr roots[highest_bit]; for (unsigned long i = 0; i < highest_bit; ++i) { roots[i] = nullptr; } @@ -196,7 +195,7 @@ class FibbonachiHeap { for (unsigned long j = 0; j < highest_bit; ++j) { if (roots[j] != nullptr) { - concat_node_lists(min_root, roots[j]); + concatenate_node_lists(min_root, roots[j]); if (roots[j]->value < min_root->value) { min_root = roots[j]; } @@ -204,7 +203,7 @@ class FibbonachiHeap { } } - void add_children_as_roots(TreeNode* node) { + void add_children_as_roots(std::shared_ptr node) { if (node->child != nullptr) { auto cur_child = node->child; do { @@ -213,7 +212,7 @@ class FibbonachiHeap { cur_child = cur_child->right_sib; } while (cur_child != node->child); - concat_node_lists(min_root, node->child); + concatenate_node_lists(min_root, node->child); node->child = nullptr; } } @@ -234,23 +233,21 @@ class FibbonachiHeap { } } - void extract_node(TreeNode* node) { + void extract_node(std::shared_ptr node) { cut_out_node(node); add_children_as_roots(node); } - void recursive_delete(TreeNode* node) { + void recursive_delete(std::shared_ptr node) { if (node == nullptr) { return; } recursive_delete(node->child); node->left_sib->right_sib = nullptr; recursive_delete(node->right_sib); - - delete node; } - void cascading_cut(TreeNode* node) { + void cascading_cut(std::shared_ptr node) { if (node == nullptr) { return; } @@ -263,7 +260,7 @@ class FibbonachiHeap { cut_out_node(node); node->mark = false; - concat_node_lists(min_root, node); + concatenate_node_lists(min_root, node); cascading_cut(parent); } else { @@ -274,36 +271,34 @@ class FibbonachiHeap { class TreeNode { public: + friend class FibonacciHeap; T value; bool mark; - TreeNode* left_sib; - TreeNode* right_sib; - TreeNode* parent; - TreeNode* child; + std::shared_ptr left_sib; + std::shared_ptr right_sib; + std::shared_ptr parent; + std::shared_ptr child; unsigned long degree; - explicit TreeNode(T value) { - this->value = value; - degree = 0; - mark = false; - pointer = std::shared_ptr(new Pointer(this)); + static std::shared_ptr create_node(T value) { + auto new_node = std::shared_ptr(new TreeNode(value)); + new_node->pointer = std::shared_ptr(new Pointer(new_node)); + new_node->left_sib = new_node->right_sib = new_node; - left_sib = right_sib = this; - parent = nullptr; - child = nullptr; + return new_node; } - TreeNode* hang(TreeNode* second_tree) { + std::shared_ptr hang(std::shared_ptr second_tree) { if (degree != second_tree->degree) { - throw std::runtime_error ("Trees should have the same degree to hang one to another"); + throw std::runtime_error("Trees should have the same degree to hang one to another"); } - TreeNode* root_tree = this; + std::shared_ptr root_tree = get_pointer()->node; if (second_tree->value < root_tree->value) { std::swap(root_tree, second_tree); } - concat_node_lists(root_tree->child, second_tree); + concatenate_node_lists(root_tree->child, second_tree); second_tree->parent = root_tree; return root_tree; @@ -314,14 +309,23 @@ class FibbonachiHeap { } private: - friend class FibbonachiHeap; std::shared_ptr pointer; + + explicit TreeNode(T value) { + this->value = value; + degree = 0; + mark = false; + pointer = nullptr; + + parent = nullptr; + child = nullptr; + } }; class Pointer { - friend class FibbonachiHeap; + friend class FibonacciHeap; public: - explicit Pointer(TreeNode* node) { + explicit Pointer(std::shared_ptr node) { this->node = node; this->valid = true; } @@ -332,12 +336,12 @@ class FibbonachiHeap { T value() { if (!is_valid()) { - throw std::runtime_error ("Invalidated pointer to an element"); + throw std::runtime_error("Invalidated pointer to an element"); } return node->value; } private: - TreeNode* node; + std::shared_ptr node; bool valid; }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d88b837..e1fbbdb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,13 +2,13 @@ cmake_minimum_required(VERSION 3.9) add_executable( unit_tests - fibbonachi_heap_test.cpp + fibonacci_heap_test.cpp main.cpp) target_link_libraries( unit_tests gtest_main - fibbonachiHeap + fibonacciHeap ) add_test( diff --git a/test/fibonacci_heap_test.cpp b/test/fibonacci_heap_test.cpp index 9dcca12..76f4f5f 100644 --- a/test/fibonacci_heap_test.cpp +++ b/test/fibonacci_heap_test.cpp @@ -3,32 +3,32 @@ // #define BOOST_TEST_MAIN -#define BOOST_TEST_MODULE testFibbonachiHeap +#define BOOST_TEST_MODULE testFibonacciHeap -#include "../src/FibbonachiHeap/FibbonachiHeap.hpp" +#include "../src/FibonacciHeap/FibonacciHeap.hpp" #include -TEST(FibbonachiHeapBasics, Constructor) { - FibbonachiHeap heap = FibbonachiHeap(); +TEST(FibonacciHeapBasics, Constructor) { + FibonacciHeap heap = FibonacciHeap(); EXPECT_EQ(heap.empty(), true); } -TEST(FibbonachiHeapBasics, Empty) { - FibbonachiHeap heap = FibbonachiHeap(); +TEST(FibonacciHeapBasics, Empty) { + FibonacciHeap heap = FibonacciHeap(); EXPECT_EQ(heap.empty(), true); heap.insert(1); EXPECT_EQ(heap.empty(), false); } -TEST(FibbonachiHeapBasics, Insert) { - FibbonachiHeap heap = FibbonachiHeap(); +TEST(FibonacciHeapBasics, Insert) { + FibonacciHeap heap = FibonacciHeap(); auto pointer = heap.insert(1); EXPECT_EQ(pointer->value(), 1); } -TEST(FibbonachiHeapBasics, GetMin) { - FibbonachiHeap heap = FibbonachiHeap(); +TEST(FibonacciHeapBasics, GetMin) { + FibonacciHeap heap = FibonacciHeap(); auto pointer = heap.insert(1); heap.insert(2); heap.insert(5); @@ -37,8 +37,8 @@ TEST(FibbonachiHeapBasics, GetMin) { EXPECT_EQ(heap.min(), 0); } -TEST(FibbonachiHeapBasics, ExtractMin) { - FibbonachiHeap heap = FibbonachiHeap(); +TEST(FibonacciHeapBasics, ExtractMin) { + FibonacciHeap heap = FibonacciHeap(); heap.insert(2); heap.insert(3); heap.insert(5); @@ -57,8 +57,8 @@ TEST(FibbonachiHeapBasics, ExtractMin) { EXPECT_EQ(heap.size(), 0); } -TEST(FibbonachiHeapBasics, Size) { - FibbonachiHeap heap = FibbonachiHeap(); +TEST(FibonacciHeapBasics, Size) { + FibonacciHeap heap = FibonacciHeap(); EXPECT_EQ(heap.size(), 0); heap.insert(1); EXPECT_EQ(heap.size(), 1); @@ -71,8 +71,8 @@ TEST(FibbonachiHeapBasics, Size) { EXPECT_EQ(heap.size(), 2); } -TEST(FibbonachiHeapBasics, Delete) { - FibbonachiHeap heap = FibbonachiHeap(); +TEST(FibonacciHeapBasics, Delete) { + FibonacciHeap heap = FibonacciHeap(); auto pointer_to_1 = heap.insert(1); heap.remove(pointer_to_1); EXPECT_EQ(pointer_to_1->is_valid(), false); @@ -86,8 +86,8 @@ TEST(FibbonachiHeapBasics, Delete) { EXPECT_EQ(heap.min(), 1); } -TEST(FibbonachiHeapAdvanced, Change) { - FibbonachiHeap heap = FibbonachiHeap(); +TEST(FibonacciHeapAdvanced, Change) { + FibonacciHeap heap = FibonacciHeap(); heap.insert(1); heap.insert(3); auto pointer_to_2 = heap.insert(2); @@ -102,9 +102,9 @@ TEST(FibbonachiHeapAdvanced, Change) { EXPECT_EQ(heap.min(), -1); } -TEST(FibbonachiHeapAdvanced, MergeEmptyToNonEmpty) { - FibbonachiHeap heap1 = FibbonachiHeap(); - FibbonachiHeap heap2 = FibbonachiHeap(); +TEST(FibonacciHeapAdvanced, MergeEmptyToNonEmpty) { + FibonacciHeap heap1 = FibonacciHeap(); + FibonacciHeap heap2 = FibonacciHeap(); heap1.insert(1); heap1.insert(3); @@ -114,9 +114,9 @@ TEST(FibbonachiHeapAdvanced, MergeEmptyToNonEmpty) { EXPECT_EQ(heap2.size(), 0); } -TEST(FibbonachiHeapAdvanced, MergeNonEmptyToEmpty) { - FibbonachiHeap heap1 = FibbonachiHeap(); - FibbonachiHeap heap2 = FibbonachiHeap(); +TEST(FibonacciHeapAdvanced, MergeNonEmptyToEmpty) { + FibonacciHeap heap1 = FibonacciHeap(); + FibonacciHeap heap2 = FibonacciHeap(); heap1.insert(1); heap1.insert(3); @@ -126,9 +126,9 @@ TEST(FibbonachiHeapAdvanced, MergeNonEmptyToEmpty) { EXPECT_EQ(heap1.size(), 0); } -TEST(FibbonachiHeapAdvanced, MergeNonEmptyToNonEmpty) { - FibbonachiHeap heap1 = FibbonachiHeap(); - FibbonachiHeap heap2 = FibbonachiHeap(); +TEST(FibonacciHeapAdvanced, MergeNonEmptyToNonEmpty) { + FibonacciHeap heap1 = FibonacciHeap(); + FibonacciHeap heap2 = FibonacciHeap(); heap1.insert(1); heap1.insert(3); @@ -141,15 +141,15 @@ TEST(FibbonachiHeapAdvanced, MergeNonEmptyToNonEmpty) { EXPECT_EQ(heap2.size(), 0); } -TEST(FibbonachiHeapExceptions, RequestsToEmptyHeap) { - FibbonachiHeap heap = FibbonachiHeap(); +TEST(FibonacciHeapExceptions, RequestsToEmptyHeap) { + FibonacciHeap heap = FibonacciHeap(); EXPECT_THROW(heap.min(), std::runtime_error); EXPECT_THROW(heap.extract_min(), std::runtime_error); } -TEST(FibbonachiHeapExceptions, RequestsToInvalidatedPointer) { - FibbonachiHeap heap = FibbonachiHeap(); +TEST(FibonacciHeapExceptions, RequestsToInvalidatedPointer) { + FibonacciHeap heap = FibonacciHeap(); auto pointer_to_1 = heap.insert(1); heap.remove(pointer_to_1);