感受最近一直在学东西来着。函数
至于缘由?学习
仍是我太弱了,每次看一道题:啥?这是什么?根本没学过啊。ui
索性这段时间就多学点新知识吧。spa
提及来,我如今最近根本不会取标题名字了,就随意一点吧。翻译
仍是这样一个一个的\(part\)写起来比较舒服。code
咱们先来理解一下\(K\)、\(D\)和\(Tree\)吧排序
首先\(Tree\)是什么?你本身回答吧。递归
而后\(K\)是什么?\(K\)固然就是\(K\)啊,仍是什么?element
\(D\)?彷佛是\(demensional\)??也就是维度的意思博客
这样就能解释为啥\(K\)就是\(K\)了
因此翻译过来就是“K维树”咯。
所以,\(KD-Tree\)用来分割\(K\)维空间,而后能够在上面搞各类各样的事情?
彷佛就是这样的。
显然的,在咱们的空间中,有一堆的点。
咱们如今要处理他们。
因此咱们选择任意一个维度排序
而后选择中间那个点的这一维来分割空间。
按照这一维排序后左右就分红了两部分。
这样子就能够分割空间了。(有一个\(STL\)的函数叫作\(nth\_element\),能够了解一下)
(据说维度不能那么随意的选择,好比你一直只按照一个维度划分彷佛就不是很好?)
(网上的博客主要是推荐按照每一个维度依次分割,若是全部维度都分割完了就再从第一个开始循环)
(彷佛还有一种更好的方法?算下方差什么的,反正我是不打算用这种啦)
咱们如今已经把空间给分割,对于每一块分割出来的空间,里面有若干个点。
咱们对于这些点维护一些信息,在回答询问的时候,利用这些信息估算一下答案,
若是最有状况下的答案不优于当前答案,咱们就不在这个空间内计算答案。
听着颇有道理?
怎么越听越以为像剪枝?
恩,好像就是剪枝诶!
因此咱们的\(KD-Tree\)也是一个暴力?
反正我是这么认为的。
首先咱们须要一个\(Build\)函数来构建\(KD-Tree\)
因而它大概长成这个样子
int Build(int l,int r,int nD) { int x=(l+r)>>1;D=nD; nth_element(&a[l],&a[x],&a[r+1]); t[x].d[0]=t[x].mn[0]=t[x].mx[0]=a[x].d[0]; t[x].d[1]=t[x].mn[1]=t[x].mx[1]=a[x].d[1]; if(l<x)ls=Build(l,x-1,nD^1),update(x,ls); if(r>x)rs=Build(x+1,r,nD^1),update(x,rs); return x; }
对于插入操做,咱们模仿\(Build\)的这个递归操做,
对于当前节点所掌控的空间进行当前维度的比较,检查应该分像左侧仍是右侧。
等等?这听起来怎么这么像\(SBT\)??反正我也是这么以为的
也许\(KD-Tree\)就是\(SBT\)在空间上的拓展???
话说回来,\(KD-Tree\)在处理实际问题的时候,不一样的剪枝函数要本身仔细思考,这样才可以更快。
据说有的时候由于插点插得太多了,致使\(KD-Tree\)变得很是的不平衡,
咱们能够相似替罪羊树同样把它推倒重建。
对于每一个节点咱们额外维护一个\(size\)
每次\(check\)一下当前节点左右子树的\(size\)的比值时候超过了设定的\(alpha\)
若是超过了直接拍扁重建一次就好啦
qaq,蜜汁不难???