- 一个比较高效和内存友好的四叉树(几何体树、划分树,多道树)
- 分象限存储boolean矩阵(可扩展为其他数据类型)
- 可用于图像处理、空间数据索引、2D中的快速碰撞检测、稀疏数据,向量线追踪等场景
- 由Modern C++ 17/20编写
- 数据结构本身支持深拷贝,子树创建,查询,插入,批量赋值,控制台输出,遍历等操作
- 使用智能指针管理,内存安全
#include <functional>
#include <array>
#include <bitset>
#include <memory>
#include <concepts>
#include <cstdint>
#include <cmath>
#include <unordered_map>
#include <stdexcept>
#include <exception>
#include <iostream>
typedef struct {
std::size_t x1, y1, x2, y2;
} retancgle;
typedef struct {
std::size_t x, y;
} coordinate;
class BooleanQuad {
friend std::ostream& operator<<(std::ostream&, const BooleanQuad&);
public:
static constexpr std::size_t __CAPACITY__ { 1 << 6 };
using __value_type__ = bool;
using __builtin_matrix_type__
= std::array<std::bitset<__CAPACITY__>, __CAPACITY__>;
private:
__builtin_matrix_type__ matrix {};
std::size_t dSize {0U};
struct Node {
bool __leaf__ {false};
bool __value__;
std::shared_ptr<Node> children[4] {nullptr};
};
std::shared_ptr<Node> root;
private:
void __Hashing__(const std::shared_ptr<Node>& O,
std::unordered_map<std::shared_ptr<Node>, Node *>& hash) {
if (!O) return;
hash[O] = new Node{ __leaf__ :
O->__leaf__,
__value__ :
O->__value__ };
for ( auto i {0U}; i < 4U; ++i)
__Hashing__(O->children[i], hash);
}
void __Rehashing__(const std::shared_ptr<Node>& O,
std::unordered_map<std::shared_ptr<Node>, Node *>& hash) {
if (!O) return;
for (auto i {0U}; i < 4U; ++i) {
hash[O]->children[i]
= std::shared_ptr<Node>(hash[O->children[i]]);
__Rehashing__(O->children[i], hash);
}
}
private:
std::ostream& output(std::ostream& Os) const {
Os << std::boolalpha;
for ( auto i {0U}; i < dSize; ++i) {
for ( auto j {0U}; j < dSize; ++j)
Os << '\t' << matrix[i][j];
Os << '\n';
}
return Os;
}
public:
constexpr BooleanQuad(void) noexcept = default;
BooleanQuad(const BooleanQuad& other)
: dSize(other.dSize) {
if (!other.root) return;
std::unordered_map<std::shared_ptr<Node>, Node *> hash;
__Hashing__(other.root, hash);
__Rehashing__(other.root, hash);
root = std::shared_ptr<Node>(hash[other.root]);
}
BooleanQuad& operator=(const BooleanQuad& other) {
if (this == &other) return *this;
dSize = other.dSize;
if (root) root.reset();
root = BooleanQuad(other).root;
}
BooleanQuad& operator=(BooleanQuad&&) noexcept = default;
template <class Tp, std::size_t N, std::size_t M>
requires std::convertible_to<Tp, bool>
constexpr BooleanQuad(Tp (&__matrix)[N][M]) noexcept {
static_assert(N == M, "dimenssion constraint: rows equals to columns");
dSize = 1U << static_cast<std::size_t>(std::log2l(N));
for (auto i {0U}; i < N; ++i) for (auto j {0U}; j < M; ++j)
matrix[i][j] = static_cast<bool>(__matrix[i][j]);
}
BooleanQuad(__builtin_matrix_type__ __matrix)
noexcept(noexcept(matrix.swap(__matrix)))
: dSize(1U << static_cast<std::size_t>(std::log2l(__matrix.size()))) {
matrix.swap(__matrix);
}
inline void construct(void) {
const auto& N { __CAPACITY__ };
std::array < std::array < uint32_t, __CAPACITY__ + 1 >, __CAPACITY__ + 1 >
prefix {};
for (auto i {1U}; i <= N; ++i) for (auto j {1U}; j <= N; ++j)
prefix[i][j] = prefix[i - 1][j]
+ prefix[i][j - 1]
- prefix[i - 1][j - 1]
+ (int)matrix[i - 1][j - 1];
#define __ARGS__ const coordinate& Os, const coordinate& Ot
#define __COORDINATES__ \
std::size_t f1 = Os.x;\
std::size_t e1 = Os.y;\
std::size_t f2 = Ot.x;\
std::size_t e2 = Ot.y;
auto Sum = [&prefix](__ARGS__) {
__COORDINATES__
return prefix[f2][e2]
- prefix[f2][e1]
- prefix[f1][e2]
+ prefix[f1][e1];
};
std::function<std::shared_ptr<Node>(__ARGS__)>
dfs = [&](__ARGS__) {
int __Sum = Sum(Os, Ot);
__COORDINATES__
return std::shared_ptr<Node>(
! __Sum ?
new Node{__leaf__ : true, __value__ : false}
: __Sum == (int)((f2 - f1) * (e2 - e1)) ?
new Node{__leaf__ : true, __value__ : true}
: new Node{
__leaf__ : false,
__value__ : false,
children :
{
dfs(
{f1, e1},
{(f1 + f2) / 2, (e1 + e2) / 2}),
dfs(
{f1, (e1 + e2) / 2},
{(f1 + f2) / 2, e2}),
dfs(
{(f1 + f2) / 2, e1},
{f2, (e1 + e2) / 2}),
dfs(
{(f1 + f2) / 2, (e1 + e2) / 2},
{f2, e2})
}
});
};
root = dfs({0U, 0U}, {dSize, dSize});
#undef __ARGS__
#undef __COORDINATES__
}
BooleanQuad SubQuad(const retancgle& rect) try {
auto [x1, y1, x2, y2] = rect;
signed w = x2 - x1;
signed h = y2 - y1;
if (!(w >= 0 && h >= 0))
throw std::invalid_argument("Geometry of rect invalid");
auto s { 1U << static_cast<std::size_t>(
std::log2l(std::max(w, h)) ) };
BooleanQuad ret;
ret.dSize = s;
for ( auto i {0U}; i < s; ++i) for ( auto j {0U}; j < s; ++j)
ret.matrix[i][j] = matrix[i + x1][j + y1];
return ret;
} catch (const std::exception& e) {
std::cerr << "[trace-back] recently called at BooleanQuad::SubQuad() :\t"
<< e.what()
<< '\n';
}
constexpr bool
Query( const coordinate& p) const {
return matrix.at(p.x)[p.y];
}
constexpr std::size_t
size(void) const noexcept {
return dSize;
}
};
inline std::ostream&
operator<<(std::ostream& Os, const BooleanQuad& Q) {
return Q.output(Os);
}