小編給大家分享一下C#通過KD樹進行距離最近點的查找的案例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

1. KD樹介紹
Kd-Tree(KD樹),即K-dimensional tree,是一種高維索引樹形數(shù)據(jù)結構,常用于在大規(guī)模的高維數(shù)據(jù)空間進行最鄰近查找和近似最鄰近查找。我實現(xiàn)的KD樹是二維的Kd - tree。目的是在點集中尋找最近點。參考資料是Kd-Tree的百度百科。并且根據(jù)百度百科的邏輯組織了代碼。
2. KD樹的數(shù)學解釋
3. KD樹的構造方法
這里是用的二維點集進行構造Kd-tree。三維的與此類似。
樹中每個節(jié)點的數(shù)據(jù)類型:
public class KDTreeNode
{
/// <summary>
/// 分裂點
/// </summary>
public Point pisionPoint { get; set; }
/// <summary>
/// 分裂類型
/// </summary>
public EnumpisionType pisionType { get; set; }
/// <summary>
/// 左子節(jié)點
/// </summary>
public KDTreeNode LeftChild { get; set; }
/// <summary>
/// 右子節(jié)點
/// </summary>
public KDTreeNode RightChild { get; set; }
}3.1 KD樹構造邏輯流程
將所有的點放入集合a中
對集合所有點的X坐標求得方差xv,Y坐標求得方差yv
如果xv > yv,則對集合a根據(jù)X坐標進行排序。如果 yv > xv,則對集合a根據(jù)y坐標進行排序。
得到排序后a集合的中位數(shù)m。則以m為斷點,將[0,m-2]索引的點放到a1集合中。將[m,a.count]索引的點放到a2的集合中(m點的索引為m-1)。
構建節(jié)點,節(jié)點的值為a[m-1],如果操作集合中節(jié)點的個數(shù)大于1,則左節(jié)點對[0,m-2]重復2-5步,右節(jié)點為對[m,a.count]重復2-5步;反之,則該節(jié)點為葉子節(jié)點。
3.2 代碼實現(xiàn)
private KDTreeNode CreateTreeNode(List<Point> pointList)
{
if (pointList.Count > 0)
{
// 計算方差
double xObtainVariance = ObtainVariance(CreateXList(pointList));
double yObtainVariance = ObtainVariance(CreateYList(pointList));
// 根據(jù)方差確定分裂維度
EnumpisionType pisionType = SortListByXOrYVariances(xObtainVariance, yObtainVariance, ref pointList);
// 獲得中位數(shù)
Point medianPoint = ObtainMedian(pointList);
int medianIndex = pointList.Count / 2;
// 構建節(jié)點
KDTreeNode treeNode = new KDTreeNode()
{
pisionPoint = medianPoint,
pisionType = pisionType,
LeftChild = CreateTreeNode(pointList.Take(medianIndex).ToList()),
RightChild = CreateTreeNode(pointList.Skip(medianIndex + 1).ToList())
};
return treeNode;
}
else
{
return null;
}
}4. KD樹搜索方法
Kd-Tree的總體搜索流程先根據(jù)普通的查找找到一個最近的葉子節(jié)點。但是這個葉子節(jié)點不一定是最近的點。再進行回溯的操作找到最近點。
4.1 KD樹搜索邏輯流程
對于根據(jù)點集構建的樹t,以及查找點p.將根節(jié)點作為節(jié)點t進行如下的操作
如果t為葉子節(jié)點。則得到最近點n的值為t的分裂點的值,跳到第5步;如果t不是葉子節(jié)點,進行第3步
則確定t的分裂方式,如果是按照x軸進行分裂,則用p的x值與節(jié)點的分裂點的x值進行比較,反之則進行Y坐標的比較
如果p的比較值小于t的比較值,則將t指定為t的左孩子節(jié)點。反之將t指定為t的右孩子節(jié)點,執(zhí)行第2步
定義檢索點m,將m設置為n
計算m與p的距離d1,n與m的距離d2。
如果d1 >= d2且有父節(jié)點,則將m的父節(jié)點作為m的值執(zhí)行5步,若沒有父節(jié)點,則得到真正的最近點TN; 如果d1 < d2就表示n點不是最近點,執(zhí)行第8步
若n有兄弟節(jié)點,則 n = n的兄弟節(jié)點;若n沒有兄弟節(jié)點,則 n = n的父節(jié)點。刪除原來的n節(jié)點。將m的值設置為新的n節(jié)點;執(zhí)行第6步。
4.2 代碼實現(xiàn)
public Point FindNearest(Point searchPoint)
{
// 按照查找方式尋找最近點
Point nearestPoint = DFSSearch(this.rootNode, searchPoint);
// 進行回溯
return BacktrcakSearch(searchPoint, nearestPoint);
}
private Point DFSSearch(KDTreeNode node,Point searchPoint,bool pushStack = true)
{
if(pushStack == true)
{
// 利用堆棧記錄查詢的路徑,由于樹節(jié)點中沒有記載父節(jié)點的原因
backtrackStack.Push(node);
}
if (node.pisionType == EnumpisionType.X)
{
return DFSXsearch(node,searchPoint);
}
else
{
return DFSYsearch(node, searchPoint);
}
}
private Point BacktrcakSearch(Point searchPoint,Point nearestPoint)
{
// 如果記錄路徑的堆棧為空則表示已經(jīng)回溯到根節(jié)點,則查到的最近點就是真正的最近點
if (backtrackStack.IsEmpty())
{
return nearestPoint;
}
else
{
KDTreeNode trackNode = backtrackStack.Pop();
// 分別求回溯點與最近點距查找點的距離
double backtrackDistance = ObtainDistanFromTwoPoint(searchPoint, trackNode.pisionPoint);
double nearestPointDistance = ObtainDistanFromTwoPoint(searchPoint, nearestPoint);
if (backtrackDistance < nearestPointDistance)
{
// 深拷貝節(jié)點的目的是為了避免損壞樹
KDTreeNode searchNode = new KDTreeNode()
{
pisionPoint = trackNode.pisionPoint,
pisionType = trackNode.pisionType,
LeftChild = trackNode.LeftChild,
RightChild = trackNode.RightChild
};
nearestPoint = DFSBackTrackingSearch(searchNode, searchPoint);
}
// 遞歸到根節(jié)點
return BacktrcakSearch(searchPoint, nearestPoint);
}
}以上是C#通過KD樹進行距離最近點的查找的案例的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
網(wǎng)頁題目:C#通過KD樹進行距離最近點的查找的案例-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://chinadenli.net/article28/shdjp.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供外貿建站、網(wǎng)站內鏈、靜態(tài)網(wǎng)站、外貿網(wǎng)站建設、網(wǎng)站營銷、做網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內容