From a145dcc108568864441cdc654758224e1c9e4969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Ke=C3=9Fler?= Date: Sat, 16 Apr 2022 11:34:29 +0200 Subject: [PATCH] implement segment tree --- CMakeLists.txt | 2 +- geometry.h | 18 ++++++++++ main.cpp | 16 --------- segment_tree.cpp | 64 +++++++++++++++++++++++++++++++++ segment_tree.h | 93 ++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 169 insertions(+), 24 deletions(-) create mode 100644 segment_tree.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c27ab1..480f5b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,6 @@ set(CMAKE_CXX_STANDARD 20) find_package(benchmark REQUIRED) -add_executable(prog main.cpp segment_tree.h geometry.h) +add_executable(prog main.cpp segment_tree.h geometry.h segment_tree.cpp) target_link_libraries(prog benchmark::benchmark) \ No newline at end of file diff --git a/geometry.h b/geometry.h index 0c2879b..d814a52 100644 --- a/geometry.h +++ b/geometry.h @@ -21,4 +21,22 @@ struct Interval { Coordinate right; }; +struct Rectangle { + Point bottom_left; + Point top_right; + + // only for algorithm + Index i_left; + Index i_right; +}; + +struct RectCoord { + Coordinate coord; + Rectangle* rect; // guaranteed to be valid at all times + bool operator<(const RectCoord &other) { + return coord < other.coord; + } +}; + + #endif //PROG_GEOMETRY_H diff --git a/main.cpp b/main.cpp index e19d361..8153a20 100644 --- a/main.cpp +++ b/main.cpp @@ -5,22 +5,6 @@ #include "geometry.h" -struct Rectangle { - Point bottom_left; - Point top_right; - - // only for algorithm - Index i_left; - Index i_right; -}; - -struct RectCoord { - Coordinate coord; - Rectangle* rect; // guaranteed to be valid at all times - bool operator<(const RectCoord &other) { - return coord < other.coord; - } -}; Unit get_area_union(std::vector rectangles) { // do some input sanity checks diff --git a/segment_tree.cpp b/segment_tree.cpp new file mode 100644 index 0000000..f454945 --- /dev/null +++ b/segment_tree.cpp @@ -0,0 +1,64 @@ +// +// Created by maximilian on 16.04.22. +// +#include +#include +#include "segment_tree.h" + +SegmentTree::SegmentTree(const std::vector &coords): + _covered_cross_section_length(0), _nodes() { + + assert(!coords.empty()); + + // reserve nodes for a full binary tree with at least as many leaves as intervals + size_t num_leaf_nodes = coords.size() -1; + size_t num_meta_nodes = std::bit_ceil(num_leaf_nodes) - 1; + + // Initialize all nodes with zero coverage and dummy interval + _nodes.resize(2 * num_meta_nodes - 1, {0, coords[num_leaf_nodes].coord, coords[num_leaf_nodes].coord}); + + // We initialize the tree from bottom up, keeping track of the index ranges + // and the length of the corresponding segment + + for(Index leaf_node_idx = 0 ; leaf_node_idx < num_leaf_nodes ; ++leaf_node_idx) { + _nodes[leaf_node_idx + num_meta_nodes].left_coord = coords[leaf_node_idx].coord; + _nodes[leaf_node_idx + num_meta_nodes].right_coord = coords[leaf_node_idx +1].coord; + } + // Note that there are remaining leafs that represent dummy ranges + for(Index node_idx = num_meta_nodes - 1; node_idx >= 0; ++node_idx) { + _nodes[node_idx].left_coord = left_child(node_idx).left_coord; + _nodes[node_idx].right_coord = right_child(node_idx).right_coord; + } + + assert(_nodes.front().left_coord == coords.front().coord); + assert(_nodes.front().right_coord == coords.back().coord); + assert(_nodes.front().segment_length() == coords.back().coord - coords.front().coord); +} + +void SegmentTree::add_interval(Interval interval, Index node_idx) { + if (interval.left <= _nodes[node_idx].left_coord && _nodes[node_idx].right_coord <= interval.right) { + update_added(node_idx); + } else { + if(interval.left < left_child(node_idx).right_coord) { + add_interval(interval, left_child_idx(node_idx)); + } + if(right_child(node_idx).left_coord < interval.right) { + add_interval(interval, right_child_idx(node_idx)); + } + } +} + +void SegmentTree::remove_interval(Interval interval, Index node_idx) { + if (interval.left <= _nodes[node_idx].left_coord && _nodes[node_idx].right_coord <= interval.right) { + update_removed(node_idx); + } else { + if(interval.left < left_child(node_idx).right_coord) { + remove_interval(interval, left_child_idx(node_idx)); + } + if(right_child(node_idx).left_coord < interval.right) { + remove_interval(interval, right_child_idx(node_idx)); + } + } +} + + diff --git a/segment_tree.h b/segment_tree.h index ed24f8b..99aeb77 100644 --- a/segment_tree.h +++ b/segment_tree.h @@ -9,13 +9,92 @@ #define PROG_SEGMENT_TREE_H -class SegmentTree { - SegmentTree(const std::vector); - - Unit length_covered_intervals(); - - void add_interval(Interval interval); - void remove_interval(Interval interval); +struct TreeNode { + unsigned coverage; + Coordinate left_coord; + Coordinate right_coord; + inline Unit segment_length(); }; + +class SegmentTree { + std::vector _nodes; + Unit _covered_cross_section_length; +public: + /** + * + * @param coords Sorted vector of coordinates + */ + SegmentTree(const std::vector& coords); + + inline Unit length_covered_intervals(); + inline void add_interval(Interval interval); + inline void remove_interval(Interval interval); + +private: + inline static Index left_child_idx(Index node_idx); + inline static Index right_child_idx(Index node_idx); + inline TreeNode& left_child(Index node_idx); + inline TreeNode& right_child(Index node_idx); + inline void update_added(Index node_idx); + inline void update_removed(Index node_idx); + void add_interval(Interval interval, Index node_idx); + void remove_interval(Interval interval, Index node_idx); + +}; + +/***************************************************** + * INLINE section + ****************************************************/ + + + +TreeNode& SegmentTree::left_child(Index node_idx) { + return _nodes[left_child_idx(node_idx)]; +} + +TreeNode& SegmentTree::right_child(Index node_idx) { + return _nodes[right_child_idx(node_idx)]; +} + +Unit SegmentTree::length_covered_intervals() { + return _covered_cross_section_length; +} + +void SegmentTree::add_interval(Interval interval) { + add_interval(interval, 0); +} + +void SegmentTree::remove_interval(Interval interval) { + remove_interval(interval, 0); +} + +void SegmentTree::update_added(Index node_idx) { + ++(_nodes[node_idx].coverage); + if(_nodes[node_idx].coverage == 1) { + _covered_cross_section_length += _nodes[node_idx].segment_length(); + } +} + +void SegmentTree::update_removed(Index node_idx) { + --(_nodes[node_idx].coverage); + if(_nodes[node_idx].coverage == 0) { + _covered_cross_section_length -= _nodes[node_idx].segment_length(); + } +} + +Index SegmentTree::left_child_idx(Index node_idx) { + return 2*node_idx + 1; +} + +Index SegmentTree::right_child_idx(Index node_idx) { + return 2*node_idx + 2; +} + + +Unit TreeNode::segment_length() { + return right_coord - left_coord; +} + + #endif //PROG_SEGMENT_TREE_H