程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C語言實現一個四叉樹(quadtree)

C語言實現一個四叉樹(quadtree)

編輯:關於C語言

用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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved