implement segment tree
This commit is contained in:
parent
402f860bbc
commit
a145dcc108
5 changed files with 169 additions and 24 deletions
|
@ -5,6 +5,6 @@ set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
find_package(benchmark REQUIRED)
|
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)
|
target_link_libraries(prog benchmark::benchmark)
|
18
geometry.h
18
geometry.h
|
@ -21,4 +21,22 @@ struct Interval {
|
||||||
Coordinate right;
|
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
|
#endif //PROG_GEOMETRY_H
|
||||||
|
|
16
main.cpp
16
main.cpp
|
@ -5,22 +5,6 @@
|
||||||
|
|
||||||
#include "geometry.h"
|
#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<Rectangle> rectangles) {
|
Unit get_area_union(std::vector<Rectangle> rectangles) {
|
||||||
// do some input sanity checks
|
// do some input sanity checks
|
||||||
|
|
64
segment_tree.cpp
Normal file
64
segment_tree.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
//
|
||||||
|
// Created by maximilian on 16.04.22.
|
||||||
|
//
|
||||||
|
#include <assert.h>
|
||||||
|
#include <bit>
|
||||||
|
#include "segment_tree.h"
|
||||||
|
|
||||||
|
SegmentTree::SegmentTree(const std::vector<RectCoord> &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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,13 +9,92 @@
|
||||||
#define PROG_SEGMENT_TREE_H
|
#define PROG_SEGMENT_TREE_H
|
||||||
|
|
||||||
|
|
||||||
class SegmentTree {
|
struct TreeNode {
|
||||||
SegmentTree(const std::vector<Coordinate>);
|
unsigned coverage;
|
||||||
|
Coordinate left_coord;
|
||||||
Unit length_covered_intervals();
|
Coordinate right_coord;
|
||||||
|
inline Unit segment_length();
|
||||||
void add_interval(Interval interval);
|
|
||||||
void remove_interval(Interval interval);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SegmentTree {
|
||||||
|
std::vector<TreeNode> _nodes;
|
||||||
|
Unit _covered_cross_section_length;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param coords Sorted vector of coordinates
|
||||||
|
*/
|
||||||
|
SegmentTree(const std::vector<RectCoord>& 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
|
#endif //PROG_SEGMENT_TREE_H
|
||||||
|
|
Loading…
Reference in a new issue