RTree源代码-c语言实现

来源:互联网 发布:网络传输协议7层和4层 编辑:程序博客网 时间:2024/05/17 20:27
前一阵做实验  要用到R树  在网上找了好多代码 都不是很理想    不过最后在一篇博客上找到了一个很靠谱  而且简单易懂   清晰明了的代码   完成了R树的构建    我把原文的代码稍稍修饰了一下   并提取出我所需要的    即R树的构建    再加上我自己写的用R树查询KNN    已经调试过了  可以运行   代码如下#include "stdafx.h"#include "math.h"#include <iostream>#define Invalid_Rect(x) ((x).bound[0] > (x).bound[2])#define MIN(a, b) ((a) < (b) ? (a) : (b))#define MAX(a, b) ((a) > (b) ? (a) : (b))#define Maxfill 3    //此处将叶子节点包含对象个数的最大值和R树分值的最大值都设为maxfill#define Minfill (Maxfill/2)  //如上的最小值#define FALSE 0#define TRUE 1using namespace std;//定义矩形框的四个界值typedef struct RTreeMBR {float bound[4];}RTreeMBR;//定义R树结点分支的结构体typedef struct RTreeBranch {RTreeMBR mbr;//分支所在的矩形框struct RTreeNode* child;//分支指向的孩子结点int leafchild; //若为叶子节点(即无孩子节点),存储对象(点)的ID。}RTreeBranch;//定义R树结点的结构体typedef struct RTreeNode{int mbrcount;//结点矩形框的个数int level;//结点的高度RTreeBranch branch[Maxfill];//结点的分支}RTreeNode;//结点划分时的结构体typedef struct RTreePartition {int partition[Maxfill+1]; int total;int minfill;  int taken[Maxfill+1];//记录小矩形框是否被划分int ncount[2];  //划分成两块的各自矩形框的个数   RTreeMBR cover[2];//划分成两块的各自总的矩形框覆盖double area[2]; //划分成两块的各自面积}RTreePartition;//搜索R树时放入优先队列(堆)的结点的结构体typedef struct Node {RTreeNode* RNode; float data;char type;int ID;}Node;RTreeBranch BranchBuf[Maxfill+1];int BranchCount;RTreeMBR CoverSplit;double CoverSplitArea;RTreePartition Partition[1];int length;void RTreeSplitNode(RTreeNode *node, RTreeBranch br, RTreeNode **new_node);//创建r-tree,初始化根RTreeNode* RTreeCreate(){RTreeNode *root=new RTreeNode;root->mbrcount=0;root->level=0;for (int i=0;i<Maxfill;i++){root->branch[i].child=NULL;}return root;}//合并两个矩形框RTreeMBR RTreeCombineRect( RTreeMBR rc1, RTreeMBR rc2 ){int i, j;RTreeMBR new_rect;for (i = 0; i < 2; i++){new_rect.bound[i] = MIN(rc1.bound[i], rc2.bound[i]);j = i + 2;new_rect.bound[j] = MAX(rc1.bound[j], rc2.bound[j]);}return new_rect;}//求矩形框的面积double RTreeRectSurfaceArea( RTreeMBR rc ){double sum = (double) 0;sum=(rc.bound[2]-rc.bound[0])*(rc.bound[3]-rc.bound[1]);return  sum;}//初始化矩形框void RTreeInitRect( RTreeMBR *rc){int i;for (i=0; i<4; i++)rc->bound[i] = (double) 0;}//初始化一个分支的矩形框和孩子指针static void _RTreeInitBranch( RTreeBranch &br ){RTreeInitRect(&br.mbr);br.child = NULL;}//初始化一个r树结点的分支个数和层数以及分支void RTreeInitNode( RTreeNode *node ){int i;node->mbrcount = 0;node->level = -1;for (i = 0; i < Maxfill; i++)_RTreeInitBranch(node->branch[i]);}//结点溢出时计算合并所有的矩形框static void _RTreeGetBranches( RTreeNode *node, RTreeBranch br){int i;for (i=0;i<Maxfill;i++){BranchBuf[i]=node->branch[i];}BranchBuf[Maxfill]=br;BranchCount=Maxfill+1;CoverSplit = BranchBuf[0].mbr;for (i=1;i<Maxfill+1;i++){CoverSplit = RTreeCombineRect(CoverSplit,BranchBuf[i].mbr);}CoverSplitArea = RTreeRectSurfaceArea(CoverSplit);RTreeInitNode(node);}//将矩形框初始化RTreeMBR RTreeNullRect(void){RTreeMBR rc;int i;rc.bound[0] = (double) 1;rc.bound[2] = (double)-1;for (i=1; i<2; i++)rc.bound[i] = rc.bound[i+2] = (double) 0;return rc;}//初始化划分p的各属性值static void _RTreeInitPart( RTreePartition *p, int maxrects, int minfill){int i;p->ncount[0] = p->ncount[1] = 0;p->cover[0] = p->cover[1] = RTreeNullRect();p->area[0] = p->area[1] = (double)0;p->total = maxrects;p->minfill = minfill;for (i=0; i<maxrects; i++){p->taken[i] = FALSE;p->partition[i] = -1;}}//将第i个矩形框分到第group组static void _RTreeClassify(int i, int group, RTreePartition *p){p->partition[i] = group;p->taken[i] = TRUE;if (p->ncount[group] == 0)p->cover[group] = BranchBuf[i].mbr;elsep->cover[group] = RTreeCombineRect(BranchBuf[i].mbr, p->cover[group]);p->area[group] = RTreeRectSurfaceArea(p->cover[group]);p->ncount[group]++;}//挑选出两组的首对矩形框(即合并起来浪费最大的)static void _RTreePickSeeds(RTreePartition *p){int i, j, seed0=0, seed1=0;double worst, waste, area[Maxfill+1];for (i=0; i<p->total; i++)area[i] = RTreeRectSurfaceArea(BranchBuf[i].mbr);worst = -CoverSplitArea - 1;for (i=0; i<p->total-1; i++){for (j=i+1; j<p->total; j++){RTreeMBR one_rect;one_rect = RTreeCombineRect(BranchBuf[i].mbr, BranchBuf[j].mbr);waste = RTreeRectSurfaceArea(one_rect) - area[i] - area[j];if (waste > worst){worst = waste;seed0 = i;seed1 = j;}}}_RTreeClassify(seed0, 0, p);_RTreeClassify(seed1, 1, p);}//进行划分static void _RTreeMethodZero( RTreePartition *p, int minfill ){int i;double biggestDiff;int group, chosen=0, betterGroup=0;_RTreeInitPart(p, BranchCount, minfill);//初始化划分p的各属性值_RTreePickSeeds(p);//挑选出两组的首对矩形框(即合并起来浪费最大的)while (p->ncount[0] + p->ncount[1] < p->total && p->ncount[0] < p->total - p->minfill && p->ncount[1] < p->total - p->minfill){biggestDiff = (double)-1.;for (i=0; i<p->total; i++){if (!p->taken[i]){RTreeMBR r, rect_0, rect_1;double growth0, growth1, diff;r = BranchBuf[i].mbr;rect_0 = RTreeCombineRect(r, p->cover[0]);rect_1 = RTreeCombineRect(r, p->cover[1]);growth0 = RTreeRectSurfaceArea(rect_0) - p->area[0]; growth1 = RTreeRectSurfaceArea(rect_1) - p->area[1];diff = growth1 - growth0;if (diff >= 0)group = 0;else{group = 1;diff = -diff;}if (diff > biggestDiff){biggestDiff = diff;chosen = i;betterGroup = group;}else if (diff==biggestDiff && p->ncount[group]<p->ncount[betterGroup]){chosen = i;betterGroup = group;}}}_RTreeClassify(chosen, betterGroup, p);//将其余矩形框依次分组}/* if one group too full, put remaining rects in the other */if (p->ncount[0] + p->ncount[1] < p->total){if (p->ncount[0] >= p->total - p->minfill)group = 1;elsegroup = 0;for (i=0; i<p->total; i++){if (!p->taken[i])_RTreeClassify(i, group, p);}}}//new一个新节点并初始化RTreeNode *RTreeNewNode(void){RTreeNode *node = new RTreeNode;RTreeInitNode(node);return node;}//将分支br插入到结点,没有分裂返回0,否则返回1int RTreeAddBranch(RTreeBranch br, RTreeNode *node, RTreeNode **new_node){int i;if (node->mbrcount<Maxfill){for (i=0;i<Maxfill;i++){if (node->branch[i].child == NULL){node->branch[i]=br;node->mbrcount++;break;}}return 0;}RTreeSplitNode(node, br, new_node);return 1;}//将缓存中的分支分别分配给结点n和qstatic void _RTreeLoadNodes( RTreeNode *r, RTreeNode *q, RTreePartition *p){int i;for (i=0; i<p->total; i++){if (p->partition[i] == 0){RTreeAddBranch(BranchBuf[i], r, NULL);}else if (p->partition[i] == 1){RTreeAddBranch(BranchBuf[i], q, NULL);}}}//分裂结点形成node和newnodevoid RTreeSplitNode(RTreeNode *node, RTreeBranch br, RTreeNode **new_node){RTreePartition *p;int level;level=node->level;_RTreeGetBranches(node, br);//结点溢出时计算合并所有的矩形框/* find partition */p = &Partition[0];/* Note: can't use MINFILL(n) below since node was cleared by GetBranches() *///进行划分_RTreeMethodZero(p, Minfill);/* put branches from buffer into 2 nodes according to chosen partition    *///划分时产生的新节点*new_node = RTreeNewNode();(*new_node)->level = node->level = level;_RTreeLoadNodes(node, *new_node, p);//将缓存中的分支分别分配给结点n和q}//挑选最合适的分支插入int RTreePickBranch( RTreeMBR rc, RTreeNode *node){RTreeMBR r;int i, first_time = 1;double increase, bestIncr=(double)-1, area, bestArea=0;int best=0;RTreeMBR tmp_rect;for (i=0; i<Maxfill; i++){if (node->branch[i].child){r = node->branch[i].mbr;area = RTreeRectSurfaceArea(r);tmp_rect = RTreeCombineRect(rc, r);increase = RTreeRectSurfaceArea(tmp_rect) - area;if (increase < bestIncr || first_time){best = i;bestArea = area;bestIncr = increase;first_time = 0;}else if (increase == bestIncr && area < bestArea){best = i;bestArea = area;bestIncr = increase;}}}return best;}//合并结点各个分支的矩形框RTreeMBR RTreeNodeCover(RTreeNode *node){int i, first_time=1;RTreeMBR rc;RTreeInitRect(&rc);for (i = 0; i < node->mbrcount; i++){if (first_time){rc = node->branch[i].mbr;first_time = 0;}else{rc = RTreeCombineRect(rc, node->branch[i].mbr);}}return rc;}//插入矩形框,static int _RTreeInsertRect( RTreeMBR rc, int tid,  RTreeNode *node, RTreeNode **new_node, int level){int i;RTreeBranch b;RTreeNode *n2;if (node->level>level){i = RTreePickBranch(rc, node);//挑选最适合的分支if (!_RTreeInsertRect(rc, tid, node->branch[i].child, &n2, level))//递归挑选最适合的分支{/* child was not split */node->branch[i].mbr = RTreeCombineRect(rc, node->branch[i].mbr);return 0;}/* child was split */node->branch[i].mbr = RTreeNodeCover(node->branch[i].child);b.child = n2;b.mbr = RTreeNodeCover(n2);return  RTreeAddBranch(b,node,new_node);}else if (node->level == level){b.mbr=rc;b.leafchild=tid;return RTreeAddBranch(b,node,new_node);//将矩形框结点插进去}return 0;}//插入矩形框。若根分裂返回1.否则返回0int RTreeInsertRect(RTreeMBR rc,int tid,RTreeNode *&root,int level){RTreeNode  *newroot;RTreeNode  *newnode;RTreeBranch b;if (_RTreeInsertRect(rc,tid,root,&newnode,level)){newroot = RTreeNewNode();  /* grow a new root, & tree taller */newroot->level = root->level + 1;b.mbr = RTreeNodeCover(root);b.child = root;RTreeAddBranch(b, newroot, NULL);b.mbr = RTreeNodeCover(newnode);b.child = newnode;RTreeAddBranch(b, newroot, NULL);root = newroot;return 1;}return 0;}void HeapAdjust(Node H[30],int s,int m){int j;Node temp = H[s];for (j = 2*s; j<=m; j*=2){if (j<m && H[j].data > H[j+1].data){j++;}if (temp.data <= H[j].data){break;}else{H[s] = H[j];s = j;}}H[s] = temp;}Node DelHeap(Node H[30]){Node temp = H[1];H[1]=H[length];length--;HeapAdjust(H,1,length);return temp;}void InsertHeap(Node H[30], Node temp){int i;length++;H[length]=temp;for (i = length/2; i > 0; i/=2){HeapAdjust(H,i,length);if (H[i].data >= H[i/2].data && i/2>0){break;}}}//计算点到矩形框的最短距离double DistRect(RTreeMBR rc1,RTreeMBR rc2){double x=rc1.bound[0];double y=rc1.bound[1];double xmin=rc2.bound[0];double xmax=rc2.bound[2];double ymin=rc2.bound[1];double ymax=rc2.bound[3];double dist,tempx,tempy;if (x>=xmin && x<=xmax && y>=ymin && y<=ymax)//当点在矩形框内为0{return 0;}else if (x>=xmin && x<=xmax){if (y>=ymax){dist=y-ymax;return dist;}else{dist=ymin-y;return dist;}}else if (y>=ymin && y<=ymax){if (x>=xmax){dist=x-xmax;return dist;}else{dist=xmin-x;return dist;}}else{if (x>=xmax && y>=ymax){tempx=pow((x-xmax),2);tempy=pow((y-ymax),2);dist=sqrt(tempx+tempy);return dist;}else if (x>=xmax && y<=ymin){tempx=pow((x-xmax),2);tempy=pow((ymin-y),2);dist=sqrt(tempx+tempy);return dist;}else if (x<=xmin && y<=ymin){tempx=pow((xmin-x),2);tempy=pow((ymin-y),2);dist=sqrt(tempx+tempy);return dist;}else {tempx=pow((xmin-x),2);tempy=pow((y-ymax),2);dist=sqrt(tempx+tempy);return dist;}}}//给定查询点,在R树上搜索最近的点void RTreeSearch(RTreeNode *node, RTreeMBR rc){int k=0;float dist=0;Node H[30];Node node1,temp;length=0;for (int i=0;i<node->mbrcount;i++){dist=DistRect(rc,node->branch[i].mbr);if (node->level>0){temp.data=dist;temp.RNode=node->branch[i].child;temp.type='N';InsertHeap(H,temp);}else{temp.data=dist;temp.ID=node->branch[i].leafchild;temp.type='Y';InsertHeap(H,temp);}}while (length >0){node1 = DelHeap(H);if (node1.type == 'N'){for (int i=0;i<node1.RNode->mbrcount;i++){dist=DistRect(rc,node1.RNode->branch[i].mbr);if (node1.RNode->level>0){temp.data=dist;temp.RNode=node1.RNode->branch[i].child;temp.type='N';InsertHeap(H,temp);}else{temp.data=dist;temp.ID=node1.RNode->branch[i].leafchild;temp.type='Y';InsertHeap(H,temp);}}}else{ k++; cout<<"据查询点第"<<k<<"近的点为:"<<node1.ID<<"   距离为:"<<node1.data<<endl; if (k == 3) { return; }}}}int _tmain(int argc, _TCHAR* argv[]){//定义要插入的点,这里用矩形表示(两个对角点重合)RTreeMBR rects[]={  {0,2,0,2},//xmin,ymin,xmax,ymax,表示点(x,y)=(0,2)   {1,2,1,2},   {3,4,3,4},   {3,5,3,5},   {4,6,4,6},   {1,3,1,3}};int msize = sizeof(rects) / sizeof(rects[0]);//要插入点的个数RTreeNode *root;root=RTreeCreate();//初始化根结点for(int i=0;i<msize;i++){RTreeInsertRect(rects[i],i,root,0);  //(待插入点的矩形框,点的ID,R树的根,level)}RTreeMBR rect={5,6,5,6};//查询点的坐标(x,y)=(5,6)RTreeSearch(root,rect);//搜索距查询点最近的点return 0;}
最后再贴上原博客的链接 <a target=_blank href="http://blog.csdn.net/ubuntu64fan/article/details/1898129">http://blog.csdn.net/ubuntu64fan/article/details/1898129</a>  里面很全   还有R树的删除等等之类的操作


0 0
原创粉丝点击