C语言实现一个四叉树quadtree
cheungmine
用C语言实现一个2维四叉树quadtree,具有一定的实际意义。你可以把几何图形的索引(用long型的id标识)放到这个树中(根据最小边界矩形)。quadtree可以用来快速区域查找图形,虽然不是那么精确,但是毕竟没有漏掉的。虽然quadtree的效率不如RTree?但是RTree的实现毕竟复杂了些,我会尽快收集整理出RTree的代码。RTree确实比QuadTree好的多?(起码RTree很时髦啊!)
头文件如下:
/*
*quadtree.h
*Quadtreestructure--forspatialquicksearching
*cheungmine
*Oct.5,2007.Allrightsreserved.
*/
#ifndefQUADTREE_H_INCLUDED
#define QUADTREE_H_INCLUDED
#include " unistd.h "
#include " list.h "
#define QUAD_SUBNODES4
#define QBOX_OVERLAP_MAX0.4
#define QBOX_OVERLAP_MIN0.02
#define QTREE_DEPTH_MAX8
#define QTREE_DEPTH_MIN4
#define QUADRANT_BITS3
/* aquadrantdefinedbelow:
NW(1)|NE(0)
-----------|-----------
SW(2)|SE(3)
*/
typedef enum
{
NE = 0 ,
NW = 1 ,
SW = 2 ,
SE = 3
}QuadrantEnum;
/* aboxdefinedbelow:
_____max
|__|__|
|__|__|
min
*/
typedef struct _quadbox_t
{
double _xmin,
_ymin,
_xmax,
_ymax;
}quadbox_t;
/* quadnode */
typedef struct _quadnode_t
{
quadbox_t_box; /* nodeboundbox */
list_t * _lst; /* nodedatalist */
struct _quadnode_t * _sub[QUAD_SUBNODES]; /* pointertosubnodesofthisnode */
}quadnode_t;
/* quadtree */
typedef struct _quadtree_t
{
quadnode_t * _root;
int _depth; /* maxdepthoftree:0-based */
float _overlap; /* overlappedratioofquanbox */
}quadtree_t;
/* =============================================================================
PublicFunctions
============================================================================= */
/* createsaquadtreeandreturnsapointertoit */
extern quadtree_t *
quadtree_create(quadbox_tbox,
int depth, /* 4~8 */
float overlap /* 0.02~0.4 */
);
/* destroysaquadtreeandfreeallmemory */
extern void
quadtree_destroy(INquadtree_t * qtree
);
/* insertsanodeidentifiedbynode_keyintoaquadtree,returnsthenodequadtreeencoding */
extern quadnode_t *
quadtree_insert(INquadtree_t * qtree,
IN long node_key,
INquadbox_t * node_box
);
/* searchesnodesinsidesearch_box */
extern void
quadtree_search(IN const quadtree_t * qtree,
INquadbox_t * search_box,
OUTlist_t * results_list
);
#endif // QUADTREE_H_INCLUDED
*quadtree.h
*Quadtreestructure--forspatialquicksearching
*cheungmine
*Oct.5,2007.Allrightsreserved.
*/
#ifndefQUADTREE_H_INCLUDED
#define QUADTREE_H_INCLUDED
#include " unistd.h "
#include " list.h "
#define QUAD_SUBNODES4
#define QBOX_OVERLAP_MAX0.4
#define QBOX_OVERLAP_MIN0.02
#define QTREE_DEPTH_MAX8
#define QTREE_DEPTH_MIN4
#define QUADRANT_BITS3
/* aquadrantdefinedbelow:
NW(1)|NE(0)
-----------|-----------
SW(2)|SE(3)
*/
typedef enum
{
NE = 0 ,
NW = 1 ,
SW = 2 ,
SE = 3
}QuadrantEnum;
/* aboxdefinedbelow:
_____max
|__|__|
|__|__|
min
*/
typedef struct _quadbox_t
{
double _xmin,
_ymin,
_xmax,
_ymax;
}quadbox_t;
/* quadnode */
typedef struct _quadnode_t
{
quadbox_t_box; /* nodeboundbox */
list_t * _lst; /* nodedatalist */
struct _quadnode_t * _sub[QUAD_SUBNODES]; /* pointertosubnodesofthisnode */
}quadnode_t;
/* quadtree */
typedef struct _quadtree_t
{
quadnode_t * _root;
int _depth; /* maxdepthoftree:0-based */
float _overlap; /* overlappedratioofquanbox */
}quadtree_t;
/* =============================================================================
PublicFunctions
============================================================================= */
/* createsaquadtreeandreturnsapointertoit */
extern quadtree_t *
quadtree_create(quadbox_tbox,
int depth, /* 4~8 */
float overlap /* 0.02~0.4 */
);
/* destroysaquadtreeandfreeallmemory */
extern void
quadtree_destroy(INquadtree_t * qtree
);
/* insertsanodeidentifiedbynode_keyintoaquadtree,returnsthenodequadtreeencoding */
extern quadnode_t *
quadtree_insert(INquadtree_t * qtree,
IN long node_key,
INquadbox_t * node_box
);
/* searchesnodesinsidesearch_box */
extern void
quadtree_search(IN const quadtree_t * qtree,
INquadbox_t * search_box,
OUTlist_t * results_list
);
#endif // QUADTREE_H_INCLUDED
实现文件如下:
/*
*quadtree.c
*Quadtreeimplementation--forspatialquicksearching
*cheungmine
*Oct.5,2007.Allrightsreserved.
*/
#include " quadtree.h "
#include < assert.h >
/* =============================================================================
PrivateFunctions
============================================================================= */
static BOOLquadbox_is_valid(quadbox_t * qb)
{
return (qb -> _xmin < qb -> _xmax && qb -> _ymin < qb -> _ymax) ? TRUE:FALSE;
}
static double quadbox_width( const quadbox_t * qb)
{
return (qb -> _xmax - qb -> _xmin);
}
static double quadbox_height( const quadbox_t * qb)
{
return (qb -> _ymax - qb -> _ymin);
}
static void quadbox_init(quadbox_t * qb,
double xmin, double ymin, double xmax, double ymax)
{
qb -> _xmin = xmin;qb -> _ymin = ymin;qb -> _xmax = xmax;qb -> _ymax = ymax;
assert(quadbox_is_valid(qb));
}
static void quadbox_inflate(quadbox_t * qb, double dx, double dy)
{
assert(dx > 0 && dy > 0 );
qb -> _xmin -= (dx / 2 );
qb -> _xmax += (dx / 2 );
qb -> _ymin -= (dy / 2 );
qb -> _ymax += (dy / 2 );
}
/* splitsthequadrantsuchasbelow:
nw(0010)|ne(0001)
----------|----------
sw(0100)|se(1000)
*/
static void quadbox_split( const quadbox_t * qb,
quadbox_t * ne,quadbox_t * nw,quadbox_t * se,quadbox_t * sw,
float overlap)
{
double dx = quadbox_width(qb) * ( 1.0 + overlap) / 2 ;
double dy = quadbox_height(qb) * ( 1.0 + overlap) / 2 ;
assert(overlap >= QBOX_OVERLAP_MIN - 0.0001 );
assert(overlap <= QBOX_OVERLAP_MAX + 0.0001 );
quadbox_init(ne,qb -> _xmax - dx,qb -> _ymax - dy,qb -> _xmax,qb -> _ymax);
quadbox_init(nw,qb -> _xmin,qb -> _ymax - dy,qb -> _xmin + dx,qb -> _ymax);
quadbox_init(sw,qb -> _xmin,qb -> _ymin,qb -> _xmin + dx,qb -> _ymin + dy);
quadbox_init(se,qb -> _xmax - dx,qb -> _ymin,qb -> _xmax,qb -> _ymin + dy);
}
/* returnsTRUEifthefirstisinsidethesenond */
static BOOLquadbox_is_inside( const quadbox_t * _first, const quadbox_t * _second)
{
return (_second -> _xmin < _first -> _xmin && _second -> _xmax > _first -> _xmax &&
_second -> _ymin < _first -> _ymin && _second -> _ymax > _first -> _ymax) ? TRUE:FALSE;
}
/* returnsTRUEiftwoquad_boxisoverlapped */
static BOOLquadbox_is_overlapped( const quadbox_t * _first, const quadbox_t * _second)
{
return (_first -> _xmin > _second -> _xmax || _first -> _xmax < _second -> _xmin ||
_first -> _ymin > _second -> _ymax || _first -> _ymax < _second -> _ymin) ? FALSE:TRUE;
}
static quadnode_t * quadnode_create( const quadbox_t * box)
{
quadnode_t * node = (quadnode_t * )calloc( 1 , sizeof (quadnode_t));
if (node)
memcpy( & (node -> _box),box, sizeof (quadbox_t));
return node;
}
static void quadnode_destroy(quadnode_t * node)
{
if (node -> _sub[NE] != 0 ){
quadnode_destroy(node -> _sub[NE]);
quadnode_destroy(node -> _sub[NW]);
quadnode_destroy(node -> _sub[SE]);
quadnode_destroy(node -> _sub[SW]);
}
if (node -> _lst)
list_destroy(node -> _lst,NULL);
free(node);
}
static void quadnode_create_child(quadnode_t * node, float overlap, int depth)
{
quadbox_tne,nw,se,sw;
assert(node);
quadbox_split( & (node -> _box), & ne, & nw, & se, & sw,overlap);
node -> _sub[NE] = quadnode_create( & ne);
node -> _sub[NW] = quadnode_create( & nw);
node -> _sub[SW] = quadnode_create( & sw);
node -> _sub[SE] = quadnode_create( & se);
}
static BOOLquadnode_has_child( const quadnode_t * node)
{
return (node -> _sub[NE] != 0 );
}
static BOOLquadnode_has_data( const quadnode_t * node)
{
return (node -> _lst && node -> _lst -> size > 0 ) ? TRUE:FALSE;
}
static void quadnode_add_data(quadnode_t * node, long node_key)
{
assert(node);
if ( ! node -> _lst)node -> _lst = list_create();
assert(node -> _lst);
list_append_node(node -> _lst,list_key_create(node_key));
}
/* insertsanodetoparentnodeoftree.returnspointertonode */
static quadnode_t * quadtree_insert_node(quadtree_t * tree,
quadnode_t * parent,
long node_key,
quadbox_t * node_box,
int * depth
)
{
if (quadbox_is_inside(node_box, & (parent -> _box)))
{
if ( ++ ( * depth) < tree -> _depth)
{
if ( ! quadnode_has_child(parent))
quadnode_create_child(parent,tree -> _overlap,( * depth));
if (quadbox_is_inside(node_box, & (parent -> _sub[NE] -> _box)))
return quadtree_insert_node(tree,parent -> _sub[NE],node_key,node_box,depth);
if (quadbox_is_inside(node_box, & (parent -> _sub[NW] -> _box)))
return quadtree_insert_node(tree,parent -> _sub[NW],node_key,node_box,depth);
if (quadbox_is_inside(node_box, & (parent -> _sub[SW] -> _box)))
return quadtree_insert_node(tree,parent -> _sub[SW],node_key,node_box,depth);
if (quadbox_is_inside(node_box, & (parent -> _sub[SE] -> _box)))
return quadtree_insert_node(tree,parent -> _sub[SE],node_key,node_box,depth);
}
/* insertsintothisnodesinceitcanNOTbeincludedinanysubnodes */
quadnode_add_data(parent,node_key);
return parent;
}
return NULL;
}
/* searchedtreenodes */
static void quadtree_search_nodes(quadnode_t * current_node,
quadbox_t * search_box,
list_t * results_list
)
{
if (quadbox_is_overlapped( & (current_node -> _box),search_box))
{
if (quadnode_has_data(current_node))
list_append_node(results_list,list_node_create(current_node));
if (quadnode_has_child(current_node))
{
quadtree_search_nodes(current_node -> _sub[NE],search_box,results_list);
quadtree_search_nodes(current_node -> _sub[NW],search_box,results_list);
quadtree_search_nodes(current_node -> _sub[SW],search_box,results_list);
quadtree_search_nodes(current_node -> _sub[SE],search_box,results_list);
}
}
}
/* =============================================================================
PublicFunctions
============================================================================= */
quadtree_t *
quadtree_create(quadbox_tbox,
int depth, /* 4~8 */
float overlap /* 0.02~0.4 */
)
{
quadtree_t * qt = NULL;
assert(depth >= QTREE_DEPTH_MIN - 0.0001 && depth <= QTREE_DEPTH_MAX + 0.0001 );
assert(overlap >= QBOX_OVERLAP_MIN - 0.0001 && overlap <= QBOX_OVERLAP_MAX + 0.0001 );
qt = (quadtree_t * )calloc( 1 , sizeof (quadtree_t));
if (qt)
{
qt -> _depth = depth;
qt -> _overlap = overlap;
quadbox_inflate( & box,quadbox_width( & box) * overlap,quadbox_height( & box) * overlap);
qt -> _root = quadnode_create( & box);
assert(qt -> _root);
if ( ! qt -> _root)
{
free(qt);
qt = NULL;
}
}
assert(qt);
return qt;
}
/* destroysaquadtree */
void
quadtree_destroy(INquadtree_t * qtree)
{
assert(qtree && qtree -> _root);
quadnode_destroy(qtree -> _root);
free(qtree);
}
/* insertsanodeintoquadtreeandreturnpointertonewnode */
quadnode_t *
quadtree_insert(INquadtree_t * qtree,
IN long node_key,
INquadbox_t * node_box
)
{
int depth = - 1 ;
return quadtree_insert_node(qtree,qtree -> _root,node_key,node_box, & depth);
}
/* searchesnodesinsidesearch_box */
void
quadtree_search(IN const quadtree_t * qtree,
INquadbox_t * search_box,
OUTlist_t * results_list
)
{
quadtree_search_nodes(qtree -> _root,search_box,results_list);
}
*quadtree.c
*Quadtreeimplementation--forspatialquicksearching
*cheungmine
*Oct.5,2007.Allrightsreserved.
*/
#include " quadtree.h "
#include < assert.h >
/* =============================================================================
PrivateFunctions
============================================================================= */
static BOOLquadbox_is_valid(quadbox_t * qb)
{
return (qb -> _xmin < qb -> _xmax && qb -> _ymin < qb -> _ymax) ? TRUE:FALSE;
}
static double quadbox_width( const quadbox_t * qb)
{
return (qb -> _xmax - qb -> _xmin);
}
static double quadbox_height( const quadbox_t * qb)
{
return (qb -> _ymax - qb -> _ymin);
}
static void quadbox_init(quadbox_t * qb,
double xmin, double ymin, double xmax, double ymax)
{
qb -> _xmin = xmin;qb -> _ymin = ymin;qb -> _xmax = xmax;qb -> _ymax = ymax;
assert(quadbox_is_valid(qb));
}
static void quadbox_inflate(quadbox_t * qb, double dx, double dy)
{
assert(dx > 0 && dy > 0 );
qb -> _xmin -= (dx / 2 );
qb -> _xmax += (dx / 2 );
qb -> _ymin -= (dy / 2 );
qb -> _ymax += (dy / 2 );
}
/* splitsthequadrantsuchasbelow:
nw(0010)|ne(0001)
----------|----------
sw(0100)|se(1000)
*/
static void quadbox_split( const quadbox_t * qb,
quadbox_t * ne,quadbox_t * nw,quadbox_t * se,quadbox_t * sw,
float overlap)
{
double dx = quadbox_width(qb) * ( 1.0 + overlap) / 2 ;
double dy = quadbox_height(qb) * ( 1.0 + overlap) / 2 ;
assert(overlap >= QBOX_OVERLAP_MIN - 0.0001 );
assert(overlap <= QBOX_OVERLAP_MAX + 0.0001 );
quadbox_init(ne,qb -> _xmax - dx,qb -> _ymax - dy,qb -> _xmax,qb -> _ymax);
quadbox_init(nw,qb -> _xmin,qb -> _ymax - dy,qb -> _xmin + dx,qb -> _ymax);
quadbox_init(sw,qb -> _xmin,qb -> _ymin,qb -> _xmin + dx,qb -> _ymin + dy);
quadbox_init(se,qb -> _xmax - dx,qb -> _ymin,qb -> _xmax,qb -> _ymin + dy);
}
/* returnsTRUEifthefirstisinsidethesenond */
static BOOLquadbox_is_inside( const quadbox_t * _first, const quadbox_t * _second)
{
return (_second -> _xmin < _first -> _xmin && _second -> _xmax > _first -> _xmax &&
_second -> _ymin < _first -> _ymin && _second -> _ymax > _first -> _ymax) ? TRUE:FALSE;
}
/* returnsTRUEiftwoquad_boxisoverlapped */
static BOOLquadbox_is_overlapped( const quadbox_t * _first, const quadbox_t * _second)
{
return (_first -> _xmin > _second -> _xmax || _first -> _xmax < _second -> _xmin ||
_first -> _ymin > _second -> _ymax || _first -> _ymax < _second -> _ymin) ? FALSE:TRUE;
}
static quadnode_t * quadnode_create( const quadbox_t * box)
{
quadnode_t * node = (quadnode_t * )calloc( 1 , sizeof (quadnode_t));
if (node)
memcpy( & (node -> _box),box, sizeof (quadbox_t));
return node;
}
static void quadnode_destroy(quadnode_t * node)
{
if (node -> _sub[NE] != 0 ){
quadnode_destroy(node -> _sub[NE]);
quadnode_destroy(node -> _sub[NW]);
quadnode_destroy(node -> _sub[SE]);
quadnode_destroy(node -> _sub[SW]);
}
if (node -> _lst)
list_destroy(node -> _lst,NULL);
free(node);
}
static void quadnode_create_child(quadnode_t * node, float overlap, int depth)
{
quadbox_tne,nw,se,sw;
assert(node);
quadbox_split( & (node -> _box), & ne, & nw, & se, & sw,overlap);
node -> _sub[NE] = quadnode_create( & ne);
node -> _sub[NW] = quadnode_create( & nw);
node -> _sub[SW] = quadnode_create( & sw);
node -> _sub[SE] = quadnode_create( & se);
}
static BOOLquadnode_has_child( const quadnode_t * node)
{
return (node -> _sub[NE] != 0 );
}
static BOOLquadnode_has_data( const quadnode_t * node)
{
return (node -> _lst && node -> _lst -> size > 0 ) ? TRUE:FALSE;
}
static void quadnode_add_data(quadnode_t * node, long node_key)
{
assert(node);
if ( ! node -> _lst)node -> _lst = list_create();
assert(node -> _lst);
list_append_node(node -> _lst,list_key_create(node_key));
}
/* insertsanodetoparentnodeoftree.returnspointertonode */
static quadnode_t * quadtree_insert_node(quadtree_t * tree,
quadnode_t * parent,
long node_key,
quadbox_t * node_box,
int * depth
)
{
if (quadbox_is_inside(node_box, & (parent -> _box)))
{
if ( ++ ( * depth) < tree -> _depth)
{
if ( ! quadnode_has_child(parent))
quadnode_create_child(parent,tree -> _overlap,( * depth));
if (quadbox_is_inside(node_box, & (parent -> _sub[NE] -> _box)))
return quadtree_insert_node(tree,parent -> _sub[NE],node_key,node_box,depth);
if (quadbox_is_inside(node_box, & (parent -> _sub[NW] -> _box)))
return quadtree_insert_node(tree,parent -> _sub[NW],node_key,node_box,depth);
if (quadbox_is_inside(node_box, & (parent -> _sub[SW] -> _box)))
return quadtree_insert_node(tree,parent -> _sub[SW],node_key,node_box,depth);
if (quadbox_is_inside(node_box, & (parent -> _sub[SE] -> _box)))
return quadtree_insert_node(tree,parent -> _sub[SE],node_key,node_box,depth);
}
/* insertsintothisnodesinceitcanNOTbeincludedinanysubnodes */
quadnode_add_data(parent,node_key);
return parent;
}
return NULL;
}
/* searchedtreenodes */
static void quadtree_search_nodes(quadnode_t * current_node,
quadbox_t * search_box,
list_t * results_list
)
{
if (quadbox_is_overlapped( & (current_node -> _box),search_box))
{
if (quadnode_has_data(current_node))
list_append_node(results_list,list_node_create(current_node));
if (quadnode_has_child(current_node))
{
quadtree_search_nodes(current_node -> _sub[NE],search_box,results_list);
quadtree_search_nodes(current_node -> _sub[NW],search_box,results_list);
quadtree_search_nodes(current_node -> _sub[SW],search_box,results_list);
quadtree_search_nodes(current_node -> _sub[SE],search_box,results_list);
}
}
}
/* =============================================================================
PublicFunctions
============================================================================= */
quadtree_t *
quadtree_create(quadbox_tbox,
int depth, /* 4~8 */
float overlap /* 0.02~0.4 */
)
{
quadtree_t * qt = NULL;
assert(depth >= QTREE_DEPTH_MIN - 0.0001 && depth <= QTREE_DEPTH_MAX + 0.0001 );
assert(overlap >= QBOX_OVERLAP_MIN - 0.0001 && overlap <= QBOX_OVERLAP_MAX + 0.0001 );
qt = (quadtree_t * )calloc( 1 , sizeof (quadtree_t));
if (qt)
{
qt -> _depth = depth;
qt -> _overlap = overlap;
quadbox_inflate( & box,quadbox_width( & box) * overlap,quadbox_height( & box) * overlap);
qt -> _root = quadnode_create( & box);
assert(qt -> _root);
if ( ! qt -> _root)
{
free(qt);
qt = NULL;
}
}
assert(qt);
return qt;
}
/* destroysaquadtree */
void
quadtree_destroy(INquadtree_t * qtree)
{
assert(qtree && qtree -> _root);
quadnode_destroy(qtree -> _root);
free(qtree);
}
/* insertsanodeintoquadtreeandreturnpointertonewnode */
quadnode_t *
quadtree_insert(INquadtree_t * qtree,
IN long node_key,
INquadbox_t * node_box
)
{
int depth = - 1 ;
return quadtree_insert_node(qtree,qtree -> _root,node_key,node_box, & depth);
}
/* searchesnodesinsidesearch_box */
void
quadtree_search(IN const quadtree_t * qtree,
INquadbox_t * search_box,
OUTlist_t * results_list
)
{
quadtree_search_nodes(qtree -> _root,search_box,results_list);
}
其中用到的文件(list.h,list.c,unistd.h)参考我的另一篇文章:
C语言实现一个简单的单向链表list