Hermes Wiki
Developer/Geospatial/Quadtrees/Fundamentals/quadtrees-for-spatial-indexing

Quadtrees for Spatial Indexing

Concept

A quadtree indexes 2D space by recursive subdivision: start with one node covering the whole bounding region, and every time a node accumulates more points than a chosen bucket-size threshold, split it into exactly four equal quadrants (the "quad" in quadtree) and redistribute its points into whichever new quadrant each falls into. Each of those quadrants recurses the same way, so dense regions end up many levels deep while sparse regions stay shallow — the tree's shape adapts to where the data actually is, unlike a geohash grid (see Geohashing for Proximity Search) or a fixed-resolution grid, which subdivide space uniformly regardless of point density.

A region query ("what's inside this box") descends only into quadrants whose bounds actually overlap the query box, pruning the rest — the same branch-and-bound principle an R-tree query uses (see R-Trees and Spatial Database Indexing), but over a data-independent, evenly-split grid rather than data-derived bounding rectangles. That's the structural difference that drives quadtrees' tradeoffs against both R-trees and geohashes: the partition boundaries are fixed by geometry (always split into four equal quadrants), not fitted to the data's actual bounding boxes.

Quadtrees are used far beyond database indexing — image compression (recursively subdividing regions of near-uniform pixel color), collision detection in game engines, and clustering map markers client-side at different zoom levels are all the same underlying structure applied to a different "what's in this region" problem.

Tradeoffs

Aspect Quadtree R-tree Geohash
Partition basis Fixed, data-independent quadrant split Data-derived bounding rectangles, can overlap Fixed, data-independent grid cells
Build cost Lower — no bounding-rectangle clustering to compute Higher — clustering and node-splitting on insert Lowest — pure string encoding
Density adaptivity High — subdivides only where points are dense Moderate — rectangles reflect data placement, but the tree isn't purpose-built around density None — every cell is the same fixed size at a given precision level
Query cost Fast region ("what's in this box") queries; weaker for exact-distance KNN Fast for range, polygon, and KNN queries alike Fast prefix scan, but boundary effects near cell edges
Native DB/index support Rare — usually a custom in-memory or application-level structure Common — PostGIS/GiST, most spatial databases Common — any ordinary string-indexed column
Typical deployment In-memory, client-side (map rendering, game engines) Server-side spatial database Server-side, sharding/bucketing at the row level

Build time favors the quadtree over the R-tree specifically because it skips the expensive bounding-rectangle clustering step — a quadtree split is a fixed geometric operation, not an optimization problem. The R-tree wins back query time on mixed workloads because its rectangles are fitted to the actual data rather than to an arbitrary fixed grid, so it prunes more precisely per query even though it costs more to build that precision in the first place.

When to use / when not to

  • Use for in-memory or client-side spatial indexing where there's no database round trip to amortize the cost against — clustering map pins at different zoom levels in a browser, or broad-phase collision detection in a game engine, are both classic quadtree use cases.
  • Use when point density varies a lot across the space and that variation matters to query performance — a quadtree naturally goes deeper only where points are dense, unlike a geohash grid where every cell is the same fixed size regardless of how crowded it is.
  • Prefer PostGIS/R-tree (via GiST) instead when the index needs to live at the database level, support polygon/line geometry (not just points), or serve a mixed query workload (range, containment, and KNN together) — see R-Trees and Spatial Database Indexing.
  • Prefer a geohash instead when the goal is simple regional bucketing or sharding with no need for adaptive density handling, and the system already has an ordinary indexed column to put it on.

Common pitfall

Unbounded recursive subdivision when many points cluster at or extremely near the exact same coordinates (a common real-world case — e.g. multiple records geocoded to a building's front door). Since a quadtree only stops splitting once a node's point count drops below the bucket threshold, a tight cluster of near-identical points can force splitting far past any useful precision, in the worst case recursing until floating-point coordinate resolution is exhausted. The standard mitigation is a hard maximum-depth cap on the tree, past which a node is allowed to exceed the bucket-size threshold rather than split further — trading a slightly slower query against that one dense leaf for a bounded, predictable tree depth everywhere else.

Engineering Lens

The quadtree's density-adaptive shape is the same underlying idea as any other data structure that trades a fixed-cost partition for a data-driven one only where the data actually demands it — a hash table's bucket resizing, a B-tree's node splitting, and a quadtree's recursive quadrant splitting are all instances of "don't pay for resolution you don't need, but add it exactly where the data is dense enough to need it." Recognizing that pattern is more transferable than any one structure's specific split rule: whenever a fixed-resolution approach (a flat grid, a geohash at one precision level) starts underperforming specifically in dense regions, a recursively-adaptive variant of the same idea is usually the fix, at the cost of the depth-bounding discipline described above.

Sources

Hermes Wiki