C语言实现一个四叉树quadtree

本文介绍了一种使用C语言实现的四叉树结构,该结构适用于空间快速搜索。四叉树通过递归地将空间划分为四个子区域来存储二维几何图形的索引,从而提高搜索效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 (1sizeof(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 (1sizeof(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、付费专栏及课程。

余额充值