近鄰搜尋之制高點樹(VP Tree)

2021-06-12 06:12:24 字數 3103 閱讀 8805

近鄰搜尋是一種很基礎的又相當重要的操作,除了資訊檢索以外,還被廣泛用於計算機視覺、機器學習等領域,如何快速有效的做近鄰查詢一直是一項熱門的研究。較早提出的方法多基於空間劃分(space partition),最具有代表性的如kd-tree(kdt),球樹等。本篇將介紹基於空間劃分方法中的一種,制高點樹(vantage point tree,vpt),最初在2023年提出,比kdt稍晚,提供了乙個不一樣的建樹思路。

和kdt一樣,vpt也是一類二叉樹,不同的是在每個節點的劃分策略。略微回顧一下kdt,它在每個節點擊擇乙個維度,根據資料點在該維度上的大小將資料均分為二。而在vpt中,首先從節點中選擇乙個資料點(可隨機選)作為制高點(vp),然後算出其它點到vp的距離大小,最後根據該距離大小將資料點均分為二。建樹演算法如下:

選擇某資料點v作為vp

計算其它點到v的距離

求出中值m,小於m的資料點分給左子樹,大於m的資料點分給右子樹

遞迴地建立左子樹和右子樹

這裡提供乙個簡單的例子如圖,框中為平面上的點,其中紅框為選中的vp,根據其它點到vp的距離進行了子樹劃分。

vpt查詢是 準確近鄰查詢,較適合範圍查詢,可方便擴充套件為k近鄰查詢。

進行近鄰查詢時,

假定查詢點為

q

,當前的制高點為

v

,距離中值為

m

,則有如下策略搜尋到

q點距離小於

r

的點集:

(1)  若 dist(q,v)+r≥m,遞迴地搜尋右子樹(球外區域)

(2)  若 dist(q,v)-r≤m,遞迴地搜尋左子樹(球內區域)

為了方便寫公式,用文本來進行證明,其實就是簡單的三角形不等式的應用。

最後上點乾貨,乙個簡易c++實現如下:

#ifndef _vptree_header_

#define _vptree_header_

#include #include #include #include #include #include //#include "fnn.h"

templateclass vptree

~vptree()

void create( const std::vector& items )

void search( const t& target, int k, std::vector* results,

std::vector* distances)

std::reverse( results->begin(), results->end() );

std::reverse( distances->begin(), distances->end() );

printf("vp search dist = %f\n",distances->at(0));

brute(target);

}void search(const t& target,std::vector* results,std::vector* distances)

int range_search(const t& target, double range, int *list, int &listnum)*/

//-debug

if(dist<=range)

} /*_tau = range;

rsearch( _root, target, hit, list, listnum);*/

return hit;

}private:

std::vector_items;

double _tau;

struct node

~node()

}* _root;

struct heapitem

int index;

double dist;

bool operator

};struct distancecomparator

bool operator()(const t& a, const t& b)

};node* buildfrompoints( int lower, int upper )

node* node = new node();

node->index = lower;

if ( upper - lower > 1 )

return node;

}double brute(const t& target)

if ( node->left == null && node->right == null )

if ( dist < node->threshold )

if ( dist + _tau >= node->threshold )

} else

if ( dist - _tau <= node->threshold )

}} void search( node* node, const t& target, int k,

std::priority_queue& heap )

if ( node->left == null && node->right == null )

if ( dist < node->threshold )

if ( dist + _tau >= node->threshold )

} else

if ( dist - _tau <= node->threshold ) }}

};#endif

利用kd樹實現最近鄰搜尋

輸入 已經構造的kd樹,目標點x 輸出 x的最近鄰 1在kd樹中找出包含目標點x的葉節點 從根結點出發,遞迴地向下訪問kd樹。若目標點x當前維的座標小於切分點的座標,則移動到左葉子結點,否則移動到右葉子結點。直到子節點為葉節點為止。2以此葉節點為 當前最近點 3遞迴地向上回退,在每個結點進行以下操作...

最近鄰查詢最優演算法 k d樹的最近鄰搜尋演算法

在k d tree樹中進行資料的k近鄰搜尋是特徵匹配的重要環節,其目的是檢索在k d tree中與待查詢點距離最近的k個資料點。最近鄰搜尋是k近鄰的特例,也就是1近鄰。將1近鄰改擴充套件到k近鄰非常容易。下面介紹最簡單的k d tree最近鄰搜尋演算法。基本的思路很簡單 首先通過二叉樹搜尋 比較待查...

統計學習方法 KD樹最近鄰搜尋

李航老師書上的的演算法說明沒怎麼看懂,看了網上的部落格,悟出一套迴圈 建立好kd樹以後的最近鄰搜尋 我想應該是這樣的 例子是李航 統計學習演算法 第三章56頁 例3.3 步驟結點查詢標記 棧內元素 本次迴圈結束後 最近點最近距離說明a bcde fg初始化000 0000 0abd m 空mdis ...