学习链接:http://www.cnblogs.com/eyeszjwang/articles/2429382.html

下面实现的kdtree支持以下操作:
(1) 插入一个节点
(2) 插入n个节点
(3) 查找距离某个给定点距离最小的K个节点。

插入的时候可能会导致树严重不平衡,这个时候会重建某个子树。

 #include <algorithm>
#include <queue> /***
_NodeType: 节点类型
_CompareFuncType: 比较函数类型,它应该接受两个_NodeType并返回0或者1
_UpdateFuncType: 更新函数类型,它有三个参数,分别表示Father,leftSon,rightSon,参数的类型的 _NodeType*
_DIMENSION: 维数
_DISTANCE_TYPE: 两个_NodeType之间距离的类型
_REBUILD_ALPHA: 这个参数用来维持树大致平衡,它应该大于50小于等于100
***/
template<class _NodeType,
class _CompareFuncType,
class _UpdateFuncType,
int _DIMENSION,
class _DISTANCE_TYPE,
int _REBUILD_ALPHA=>
class KDTree
{
private:
struct TreeNode
{
TreeNode(const _NodeType& _Node):m_Left(nullptr),m_Right(nullptr),m_Size(),
m_Node(_Node) {}
TreeNode() {} _NodeType m_Node;
TreeNode* m_Left;
TreeNode* m_Right;
unsigned int m_Size;
}; TreeNode* NewNode(const _NodeType& _Node)
{
return new TreeNode(_Node);
} public:
KDTree(_CompareFuncType** _CompareFuncs,_UpdateFuncType* _UpdateFunc):m_Root(nullptr)
{
for(unsigned int Idx=;Idx<_DIMENSION;++Idx)
{
m_CompareFuncs[Idx]=_CompareFuncs[Idx];
}
m_UpdateFunc=_UpdateFunc;
} void insert(const _NodeType& _Value)
{
TreeNode* BadTreeNode=nullptr;
TreeNode* BadTreeNodeParent=nullptr;
unsigned int BadTreeNodeDimension=;
m_Root=Insert(m_Root,NewNode(_Value),,
BadTreeNode,BadTreeNodeParent,BadTreeNodeDimension); if(BadTreeNode!=nullptr)
{
if(BadTreeNodeParent==nullptr)
{
m_Root=RebuildTree(BadTreeNode,BadTreeNodeDimension);
}
else
{
BadTreeNodeParent=RebuildTree(BadTreeNode,BadTreeNodeDimension);
}
}
} template<class _NodeTypeBegin>
void insert(_NodeTypeBegin _ValueArray,const unsigned int _ValueArraySize)
{
if(_ValueArraySize<=) return;
if(m_Root==nullptr)
{
m_Root=BuildGroup(_ValueArray,,_ValueArraySize-,);
}
else
{
if(m_Root->m_Size<=(unsigned int)(_ValueArraySize*_REBUILD_ALPHA/))
{
_NodeType* NewValueArray=new _NodeType[_ValueArraySize+m_Root->m_Size];
unsigned int NewValueArraySize=StoreSubtreeNodeIntoArray(m_Root,NewValueArray);
ClearSubTrees(m_Root);
for(unsigned int Idx=;Idx<_ValueArraySize;++Idx)
{
NewValueArray[NewValueArraySize++]=_ValueArray[Idx];
}
m_Root=BuildGroup(NewValueArray,,NewValueArraySize-,);
delete[] NewValueArray;
}
else
{
for(unsigned int Idx=;Idx<_ValueArraySize;++Idx)
{
insert(_ValueArray[Idx]);
}
}
}
} /***
查找距离_Value "最近" 的_SearchNumber个元素 存储在_StoreAnswerArray _ComputeMinDistanceFunc接受两个_NodeType(first,second) 用来计算second范围内所有点到first的 "最近"距离
_DISTANCE_TYPE是它的返回值类型
_ComputeDistanceFunc接受两个_NodeType(first,second) 计算first和second的距离
_DISTANCE_TYPE是它的返回值类型
_CompareDistanceFunc它接受两个_DISTANCE_TYPE(first,second) 并返回0或者1
1表示first小于second
函数返回查找到的元素个数(有可能小于_SearchNumber)
***/
template<class _ComputeDistanceFuncType,
class _CompareDistanceFuncType>
unsigned int searchKNear(const _NodeType& _Value,_NodeType* _StoreAnswerArray,
const unsigned int _SearchNumber,_CompareDistanceFuncType* _CompareDistanceFunc,
_ComputeDistanceFuncType* _ComputeMinDistanceFunc,
_ComputeDistanceFuncType* _ComputeDistanceFunc)
{
if(_SearchNumber==) return ;
unsigned int AnswerArrayElementNumber=;
SearchKNear(m_Root,_Value,_StoreAnswerArray,AnswerArrayElementNumber,_SearchNumber,
_CompareDistanceFunc,_ComputeMinDistanceFunc,_ComputeDistanceFunc);
return AnswerArrayElementNumber;
} unsigned int size() const
{
if(m_Root) return m_Root->m_Size;
return ;
} private:
template<class _ComputeDistanceFuncType,
class _CompareDistanceFuncType>
void SearchKNear(
TreeNode* _Root,const _NodeType& _Value,_NodeType* _StoreAnswerArray,
unsigned int &_CurAnswerArrayElementNumber,
const unsigned int _SearchNumber,_CompareDistanceFuncType* _CompareDistanceFunc,
_ComputeDistanceFuncType* _ComputeMinDistanceFunc,
_ComputeDistanceFuncType* _ComputeDistanceFunc)
{
if(_Root==nullptr) return;
if(_CurAnswerArrayElementNumber==)
{
_StoreAnswerArray[]=_Root->m_Node;
++_CurAnswerArrayElementNumber;
}
else
{
_DISTANCE_TYPE CurNodeDis=_ComputeDistanceFunc(_Value,_Root->m_Node);
for(unsigned int Idx=_CurAnswerArrayElementNumber-;;--Idx)
{
_DISTANCE_TYPE PreNodeDis=_ComputeDistanceFunc(_Value,_StoreAnswerArray[Idx]);
if(_CompareDistanceFunc(CurNodeDis,PreNodeDis))
{
if(Idx+<_SearchNumber)
{
_StoreAnswerArray[Idx+]=_StoreAnswerArray[Idx];
}
}
else
{
if(Idx+<_SearchNumber) _StoreAnswerArray[Idx+]=_Root->m_Node;
if(_CurAnswerArrayElementNumber<_SearchNumber)
{
++_CurAnswerArrayElementNumber;
}
break;
}
if(==Idx)
{
_StoreAnswerArray[]=_Root->m_Node;
if(_CurAnswerArrayElementNumber<_SearchNumber)
{
++_CurAnswerArrayElementNumber;
}
break;
}
}
}
if(_Root->m_Left&&_Root->m_Right)
{
_DISTANCE_TYPE LSonMinDis=_ComputeMinDistanceFunc(_Value,_Root->m_Left->m_Node);
_DISTANCE_TYPE RSonMinDis=_ComputeMinDistanceFunc(_Value,_Root->m_Right->m_Node);
_DISTANCE_TYPE CurMaxDis=_ComputeDistanceFunc(
_Value,_StoreAnswerArray[_CurAnswerArrayElementNumber-]); if(_CompareDistanceFunc(LSonMinDis,RSonMinDis))
{
if(_CurAnswerArrayElementNumber<_SearchNumber||_CompareDistanceFunc(LSonMinDis,CurMaxDis))
{
SearchKNear(_Root->m_Left,_Value,_StoreAnswerArray,_CurAnswerArrayElementNumber,
_SearchNumber,_CompareDistanceFunc,_ComputeMinDistanceFunc,
_ComputeDistanceFunc);
}
CurMaxDis=_ComputeDistanceFunc(
_Value,_StoreAnswerArray[_CurAnswerArrayElementNumber-]);
if(_CurAnswerArrayElementNumber<_SearchNumber||_CompareDistanceFunc(RSonMinDis,CurMaxDis))
{
SearchKNear(_Root->m_Right,_Value,_StoreAnswerArray,_CurAnswerArrayElementNumber,
_SearchNumber,_CompareDistanceFunc,_ComputeMinDistanceFunc,
_ComputeDistanceFunc);
}
}
else
{
if(_CurAnswerArrayElementNumber<_SearchNumber||_CompareDistanceFunc(RSonMinDis,CurMaxDis))
{
SearchKNear(_Root->m_Right,_Value,_StoreAnswerArray,_CurAnswerArrayElementNumber,
_SearchNumber,_CompareDistanceFunc,_ComputeMinDistanceFunc,
_ComputeDistanceFunc);
}
CurMaxDis=_ComputeDistanceFunc(
_Value,_StoreAnswerArray[_CurAnswerArrayElementNumber-]);
if(_CurAnswerArrayElementNumber<_SearchNumber||_CompareDistanceFunc(LSonMinDis,CurMaxDis))
{
SearchKNear(_Root->m_Left,_Value,_StoreAnswerArray,_CurAnswerArrayElementNumber,
_SearchNumber,_CompareDistanceFunc,_ComputeMinDistanceFunc,
_ComputeDistanceFunc);
}
}
}
else if(_Root->m_Left)
{
_DISTANCE_TYPE LSonMinDis=_ComputeMinDistanceFunc(_Value,_Root->m_Left->m_Node);
_DISTANCE_TYPE CurMaxDis=_ComputeDistanceFunc(
_Value,_StoreAnswerArray[_CurAnswerArrayElementNumber-]);
if(_CurAnswerArrayElementNumber<_SearchNumber||_CompareDistanceFunc(LSonMinDis,CurMaxDis))
{
SearchKNear(_Root->m_Left,_Value,_StoreAnswerArray,_CurAnswerArrayElementNumber,
_SearchNumber,_CompareDistanceFunc,_ComputeMinDistanceFunc,
_ComputeDistanceFunc);
}
}
else if(_Root->m_Right)
{
_DISTANCE_TYPE RSonMinDis=_ComputeMinDistanceFunc(_Value,_Root->m_Right->m_Node);
_DISTANCE_TYPE CurMaxDis=_ComputeDistanceFunc(
_Value,_StoreAnswerArray[_CurAnswerArrayElementNumber-]);
if(_CurAnswerArrayElementNumber<_SearchNumber||_CompareDistanceFunc(RSonMinDis,CurMaxDis))
{
SearchKNear(_Root->m_Right,_Value,_StoreAnswerArray,_CurAnswerArrayElementNumber,
_SearchNumber,_CompareDistanceFunc,_ComputeMinDistanceFunc,
_ComputeDistanceFunc);
}
}
} unsigned int StoreSubtreeNodeIntoArray(TreeNode* _Root,_NodeType* _NodeArray)
{
if(_Root==nullptr) return ;
unsigned int NodeArraySize=;
std::queue<TreeNode*> TmpQue;
TmpQue.push(_Root);
_NodeArray[NodeArraySize++]=_Root->m_Node;
while(!TmpQue.empty())
{
TreeNode* Tmp=TmpQue.front(); TmpQue.pop();
if(Tmp->m_Left)
{
TmpQue.push(Tmp->m_Left);
_NodeArray[NodeArraySize++]=Tmp->m_Left->m_Node;
}
if(Tmp->m_Right)
{
TmpQue.push(Tmp->m_Right);
_NodeArray[NodeArraySize++]=Tmp->m_Right->m_Node;
}
}
return NodeArraySize;
} void ClearSubTrees(TreeNode* _Root)
{
if(_Root)
{
if(_Root->m_Left) ClearSubTrees(_Root->m_Left);
if(_Root->m_Right) ClearSubTrees(_Root->m_Right);
delete _Root;
}
} TreeNode* RebuildTree(TreeNode* _Root,const unsigned int _Dimension)
{
_NodeType* TmpPool=new _NodeType[_Root->m_Size];
unsigned int TmpPoolSize=StoreSubtreeNodeIntoArray(_Root,TmpPool);
ClearSubTrees(_Root);
if(TmpPoolSize==) return nullptr;
TreeNode* Tmp=BuildGroup(TmpPool,,TmpPoolSize-,_Dimension);
delete[] TmpPool;
return Tmp;
} template<class _NodeTypeBegin>
TreeNode* BuildGroup(_NodeTypeBegin _TmpPool,const unsigned int _Left,const unsigned int _Right,const unsigned int _CurLayerDimention)
{
if(_Left>_Right) return nullptr; const unsigned int MidPos=(_Left+_Right)>>;
std::nth_element(_TmpPool+_Left,_TmpPool+MidPos,_TmpPool+_Right+,
m_CompareFuncs[_CurLayerDimention]); TreeNode* CurNode=NewNode(_TmpPool[MidPos]);
if(_Left+<=MidPos)
{
CurNode->m_Left=BuildGroup(_TmpPool,_Left,MidPos-,(_CurLayerDimention+)%_DIMENSION);
}
CurNode->m_Right=BuildGroup(_TmpPool,MidPos+,_Right,(_CurLayerDimention+)%_DIMENSION); PushUp(CurNode);
return CurNode;
} void PushUp(TreeNode* _Root)
{
if(_Root)
{
_Root->m_Size=+SonSize(_Root->m_Left)+SonSize(_Root->m_Right);
_NodeType *LsonNode=_Root->m_Left?&(_Root->m_Left->m_Node):nullptr;
_NodeType *RsonNode=_Root->m_Right?&_Root->m_Right->m_Node:nullptr;
m_UpdateFunc(&_Root->m_Node,LsonNode,RsonNode);
}
} TreeNode* Insert(
TreeNode* _Root,
TreeNode* _InsertNode,
const unsigned int _CurLayerDimention,
TreeNode* &_BadTreeNode,
TreeNode* &_BadTreeNodeParent,
unsigned int& _BadTreeNodeDimension)
{
if(nullptr==_Root)
{
PushUp(_InsertNode);
return _InsertNode;
}
if(m_CompareFuncs[_CurLayerDimention](_InsertNode->m_Node,_Root->m_Node))
{
_Root->m_Left=Insert(_Root->m_Left,_InsertNode,(_CurLayerDimention+)%_DIMENSION,
_BadTreeNode,_BadTreeNodeParent,_BadTreeNodeDimension);
}
else
{
_Root->m_Right=Insert(_Root->m_Right,_InsertNode,(_CurLayerDimention+)%_DIMENSION,
_BadTreeNode,_BadTreeNodeParent,_BadTreeNodeDimension);
} PushUp(_Root); if(_BadTreeNode==nullptr)
{
if(IsSeriousBadTree(_Root))
{
_BadTreeNode=_Root;
_BadTreeNodeDimension=_CurLayerDimention;
}
}
else if(_BadTreeNode==_Root->m_Left||_BadTreeNode==_Root->m_Right)
{
_BadTreeNodeParent=_Root;
}
return _Root;
} unsigned int SonSize(TreeNode* _Node)
{
if(_Node==nullptr) return ;
return _Node->m_Size;
} bool IsSeriousBadTree(TreeNode* _Root)
{
if(SonSize(_Root)==) return false;
return std::max(SonSize(_Root->m_Left),SonSize(_Root->m_Right))
>=(unsigned int)(SonSize(_Root)*_REBUILD_ALPHA/)+;
} TreeNode* m_Root;
_CompareFuncType* m_CompareFuncs[_DIMENSION];
_UpdateFuncType* m_UpdateFunc;
};

下面是一个简单的测试代码,两个点之间的距离定义为曼哈顿距离。

 struct node
{
int x,y;
int MinX,MaxX,MinY,MaxY; node(int _x=,int _y=):x(_x),y(_y) {} }; typedef int Func(const node&,const node&);
typedef void Func1(node*,node*,node*); int cmp0(const node &a,const node &b)
{
return a.x<b.x;
} int cmp1(const node &a,const node &b)
{
return a.y<b.y;
} void pushUp(node *Fa,node *lson,node *rson)
{
Fa->MinX=Fa->MaxX=Fa->x;
Fa->MinY=Fa->MaxY=Fa->y;
for(int i=;i<;++i)
{
node* p=i==?lson:rson;
if(!p) continue; Fa->MinX=min(Fa->MinX,p->MinX);
Fa->MaxX=max(Fa->MaxX,p->MaxX);
Fa->MinY=min(Fa->MinY,p->MinY);
Fa->MaxY=max(Fa->MaxY,p->MaxY);
}
} int caldis(const node &a,const node &b)
{
return abs(a.x-b.x)+abs(a.y-b.y);
} int calMinDis(const node &a,const node &b)
{
int xx=;
int yy=;
if(a.x<b.MinX) xx=b.MinX-a.x;
else if(a.x>b.MaxX) xx=a.x-b.MaxX; if(a.y<b.MinY) yy=b.MinY-a.y;
else if(a.y>b.MaxY) yy=a.y-b.MaxY; return xx+yy;
} int cmp(int x,int y)
{
return x<y;
} int main()
{
Func* funs[]={cmp0,cmp1};
KDTree<node,Func,Func1,,int> *T=
new KDTree<node,Func,Func1,,int>(funs,pushUp); node a[]={node(,),node(-,),node(,),node(,)};
T->insert(a,);
T->insert(node(,));
unsigned int Num=T->searchKNear(node(,),a,,cmp,calMinDis,caldis);
for(unsigned int Idx=;Idx<Num;++Idx)
{
printf("%d %d\n",a[Idx].x,a[Idx].y);
}
/**
5 6
5 9
2 3
**/
}

KDTree的更多相关文章

  1. hdu-5992 Finding Hotels(kd-tree)

    题目链接: Finding Hotels Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 102400/102400 K (Java/ ...

  2. bzoj 2648 KD-tree

    稍微看了一下KD-tree的讲义,大概明白了它的原理,但是实现不出来... 所以无耻的抄了一下黄学长的... #include<iostream> #include<cstdio&g ...

  3. 【BZOJ-1941】Hide and Seek KD-Tree

    1941: [Sdoi2010]Hide and Seek Time Limit: 16 Sec  Memory Limit: 162 MBSubmit: 830  Solved: 455[Submi ...

  4. 【BZOJ-4520】K远点对 KD-Tree + 堆

    4520: [Cqoi2016]K远点对 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 490  Solved: 237[Submit][Status ...

  5. BZOJ 2648 SJY摆棋子 ——KD-Tree

    [题目分析] KD-Tree第一题,其实大概就是搜索剪枝的思想,在随机数据下可以表现的非常好NlogN,但是特殊数据下会达到N^2. 精髓就在于估价函数get以及按照不同维度顺序划分的思想. [代码] ...

  6. BZOJ 2716 [Violet 3]天使玩偶 ——KD-Tree

    [题目分析] KD-Tree的例题.同BZOJ2648. [代码] #include <cstdio> #include <cstring> #include <cstd ...

  7. BZOJ 2626 & KDtree

    题意: 二维平面n个点 每次给出一个点询问距离第k小的点. SOL: kdtree裸题,抄了一发别人的模板...二维割起来还是非常显然的.膜rzz的论文. 不多说了吧.... Code: /*==== ...

  8. 【kd-tree】bzoj4154 [Ipsc2015]Generating Synergy

    区间修改的kd-tree,打标记,下传. 每次询问的时候,从询问点向上找到根,然后依次下传下来,再回答询问. #include<cstdio> #include<algorithm& ...

  9. BZOJ 2648: SJY摆棋子 kdtree

    2648: SJY摆棋子 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=2648 Description 这天,SJY显得无聊.在家自己玩 ...

  10. Kd-tree算法原理

    参考资料: Kd Tree算法原理 Kd-Tree,即K-dimensional tree,是一棵二叉树,树中存储的是一些K维数据.在一个K维数据集合上构建一棵Kd-Tree代表了对该K维数据集合构成 ...

随机推荐

  1. Cortex-R5

    TCM:Tightly Coupled Memory,连接到RAM等memory中,但是CPU读写速度很快. ECC:Error Checking and Correction PMU:Perform ...

  2. php基础知识和函数

    <?php /* echo "hello","aaaa"; //输出语法,可以输出多个字符串 print "world"; //可以输 ...

  3. 一个容易被忽略的ReportingService超时问题

    我们在使用Sql Server Reporting Service开发报表的时候,经常会遇到报表超时的问题,报表超时的原因有很多,也有很多地方可以设置报表的超时时间,比如在报表中的数据源(dataso ...

  4. 某硕笔试题mysql数据库部分(较为全面)

    Student(S#,Sname,Sage,Ssex) 学生表  Course(C#,Cname,T#) 课程表  SC(S#,C#,score) 成绩表  Teacher(T#,Tname) 教师表 ...

  5. Bootstrap:弹出框和提示框效果以及代码展示

    前言:对于Web开发人员,弹出框和提示框的使用肯定不会陌生,比如常见的表格新增和编辑功能,一般常见的主要有两种处理方式:行内编辑和弹出框编辑.在增加用户体验方面,弹出框和提示框起着重要的作用,如果你的 ...

  6. jar包里查找指定的class文件,排查是否存在或重复,工具软件:Java Class Finder

    jar包里查找指定的class文件,排查是否存在或重复,工具软件:Java Class Finder 1,下载工具地址:www.idesksoft.com/classfinder.html,如图: 2 ...

  7. 多拉A梦——日语歌词

    こんなこといいな できたらいいな 这件事真好啊 能够做到的话就好啦 あんな梦(ゆめ) こんな梦(ゆめ) いっぱいあるけど 那样的梦想 这样的梦想 我还有好多哪 みんなみんなみんな かなえてくれる 大家 ...

  8. APP运营推广那点事【干货】

    你的手机里面有多少应用?什么样的手机应用吸引你?下载之后经常用还是让他shi在那里?又或者刚点进去就卸载? 一款成功的应用,开发APP只是第一步,比前者更重要的是“养”APP,APP就像是一个需要不断 ...

  9. [原创]南水之源A*(A-Star)算法

    开发导航之前我看了一些A*(A-Star)算法的例子和讲解.没有求得甚解!不过也从A*(A-Star)算法中得到启发,写了一套自己的A*(A-Star)算法.当然,这不是真正(我也不知道)的A*(A- ...

  10. 杭电1013-Digitai Root(另解)

    #include<stdio.h>#define maxsize 1000 int main(){    char N[maxsize+1];    int i,j,sum,n;    c ...