C语言实现一个四叉树quadtree

C语言实现一个四叉树quadtree

cheungmine

 用C语言实现一个2维四叉树quadtree,具有一定的实际意义。你可以把几何图形的索引(用long型的id标识)放到这个树中(根据最小边界矩形)。quadtree可以用来快速区域查找图形,虽然不是那么精确,但是毕竟没有漏掉的。虽然quadtree的效率不如RTree?但是RTree的实现毕竟复杂了些,我会尽快收集整理出RTree的代码。RTree确实比QuadTree好的多?(起码RTree很时髦啊!)

头文件如下:

 

/*
 * quadtree.h
 *        Quad tree structure -- for spatial quick searching
 *        cheungmine 
 *      Oct. 5, 2007.  All rights reserved.
 
*/
#ifndef QUADTREE_H_INCLUDED
#define  QUADTREE_H_INCLUDED

#include 
" unistd.h "

#include 
" list.h "

#define  QUAD_SUBNODES        4

#define  QBOX_OVERLAP_MAX    0.4
#define  QBOX_OVERLAP_MIN    0.02

#define  QTREE_DEPTH_MAX        8
#define  QTREE_DEPTH_MIN        4

#define  QUADRANT_BITS        3

/*  a quadrant defined below:
          
        NW(1)   |    NE(0)
        -----------|-----------
        SW(2)   |    SE(3)
*/
typedef 
enum
{
    NE 
=   0 ,
    NW 
=   1 ,
    SW 
=   2 ,
    SE 
=   3
}QuadrantEnum;

/*  a box defined below:
           _____max
          |__|__|
          |__|__| 
   min
*/
typedef 
struct  _quadbox_t
{    
    
double     _xmin, 
            _ymin, 
            _xmax, 
            _ymax;
}quadbox_t;

/*  quad node  */
typedef 
struct  _quadnode_t
{
    quadbox_t             _box;                        
/*  node bound box  */
    list_t                
* _lst;                         /*  node data list  */
    
struct  _quadnode_t     * _sub[QUAD_SUBNODES];         /*  pointer to subnodes of this node  */
}quadnode_t;

/*  quad tree  */
typedef 
struct  _quadtree_t
{
    quadnode_t        
* _root;
    
int                  _depth;                    /*  max depth of tree: 0-based  */
    
float              _overlap;                    /*  overlapped ratio of quanbox  */     
}quadtree_t;


/* =============================================================================
                        Public Functions
=============================================================================
*/
/*  creates a quadtree and returns a pointer to it  */
extern   quadtree_t *
quadtree_create (quadbox_t    box, 
                 
int         depth,   /*  4~8  */
                 
float         overlap  /*  0.02 ~ 0.4  */
                 );

/*  destroys a quad tree and free all memory  */
extern    void
quadtree_destroy (IN  quadtree_t        
* qtree
                  );

/*  inserts a node identified by node_key into a quadtree, returns the node quadtree encoding  */
extern   quadnode_t  *
quadtree_insert (IN  quadtree_t            
* qtree, 
                 IN  
long                  node_key, 
                 IN  quadbox_t            
* node_box
                 );
 
/*  searches nodes inside search_box  */
extern    void
quadtree_search (IN  
const  quadtree_t     * qtree, 
                  IN  quadbox_t            
* search_box, 
                 OUT list_t                
* results_list
                 );

#endif   //  QUADTREE_H_INCLUDED

 

实现文件如下:

 

/*
 * quadtree.c
 *        Quad tree implementation -- for spatial quick searching
 *        cheungmine 
 *      Oct. 5, 2007.  All rights reserved.
 
*/
#include 
" quadtree.h "
#include 
< assert.h >

/* =============================================================================
                        Private Functions
=============================================================================
*/
static  BOOL quadbox_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 );
}

/*  splits the quadrant such as below:
      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);
}

/*  returns TRUE if the first is inside the senond  */
static  BOOL quadbox_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;
}

/*  returns TRUE if two quad_box is overlapped  */
static  BOOL quadbox_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_t ne, 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  BOOL quadnode_has_child( const  quadnode_t *  node)
{
    
return  (node -> _sub[NE]  !=   0 );
}

static  BOOL quadnode_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));
}

/*  inserts a node to parent node of tree. returns pointer to node  */
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);
        }

        
/*  inserts into this node since it can NOT be included in any subnodes  */
        quadnode_add_data (parent, node_key);
        
return  parent;
    }

    
return  NULL;
}


/*  searched tree nodes  */
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);
        }
    }
}


/* =============================================================================
                        Public Functions
=============================================================================
*/
quadtree_t
*
quadtree_create (quadbox_t    box, 
                 
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;
}

/*  destroys a quad tree  */
void
quadtree_destroy (IN  quadtree_t    
* qtree)
{
    assert (qtree 
&&  qtree -> _root);
    quadnode_destroy (qtree
-> _root);
    free (qtree);
}

/*  inserts a node into quadtree and return pointer to new node  */
quadnode_t 
*
quadtree_insert (IN  quadtree_t        
* qtree, 
                 IN  
long              node_key, 
                 IN  quadbox_t        
* node_box
                 )
{
    
int         depth  =   - 1 ;
    
return  quadtree_insert_node (qtree, qtree -> _root, node_key, node_box,  & depth);    
}
 
/*  searches nodes inside search_box  */
void
quadtree_search (IN  
const  quadtree_t     * qtree, 
                  IN  quadbox_t            
* search_box, 
                 OUT list_t                
* results_list
                 )
{
    quadtree_search_nodes (qtree
-> _root, search_box, results_list);
}

 

其中用到的文件(list.h,list.c,unistd.h)参考我的另一篇文章:

C语言实现一个简单的单向链表list

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

车斗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值