学习链接: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. NOIP200301乒乓球

    NOIP200301乒乓球 [问题背景] 国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及.其中11分制改革引起了很大的争议,有一部分球 员因为无法适应新规则只能 ...

  2. 【GDI+】 线段 文字 定位的问题(二)

    继续: 经过上文的分析,似乎可以得到类似这样的想法: 由此 分为左右两侧进行区分绘制,应该就可以获得想要的结果了~

  3. struct termios结构体【转】

    本文转载自:http://blog.csdn.net/vevenlcf/article/details/51096122 一.数据成员 termios 函数族提供了一个常规的终端接口,用于控制非同步通 ...

  4. 关于全站https必要性http流量劫持、dns劫持等相关技术

    关于全站https必要性http流量劫持.dns劫持等相关技术 微信已经要求微信支付,申请退款功能必须12月7号之前必须使用https证书了(其他目前为建议使用https),IOS也是2017年1月1 ...

  5. win32 treeview

    // 1.create treeview DWORD dwStryle = WS_VISIBLE | WS_CHILD | TVS_HASLINES|TVS_SHOWSELALWAYS/*|TVS_L ...

  6. Linux MTD系统剖析【转】

    转自:http://blog.csdn.net/lwj103862095/article/details/21545791 版权声明:本文为博主原创文章,未经博主允许不得转载. MTD,Memory ...

  7. 高级工具gprof、gprof2dot.py、dot

    可以研究程序性能.函数调用堆栈等,而且能用图标查看. linux环境下 C++性能测试工具 gprof + kprof + gprof2dot - 阁子 - 博客园 gprof.gprof2dot.p ...

  8. java正则表达式四种常用的处理方式是怎么样呢《匹配、分割、代替、获取》

    java 正则表达式高级篇,介绍四种常用的处理方式:匹配.分割.替代.获取,具体内容如下package test; import java.util.regex.Matcher; import jav ...

  9. PHP 页面编码声明与用header或meta实现PHP页面编码的区别

    php的header来定义一个php页面为utf编码或GBK编码 php页面为utf编码 header("Content-type: text/html; charset=utf-8&quo ...

  10. JavaScript DOM 编程艺术(第2版)读书笔记(4)

    案例研究:JavaScript 图片库 改变图片的src属性的两种方式: 1,setAttribute方法是“第1级DOM”的组成部分,它可以设置元素节点的任意属性. 2,element.src = ...