中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#如何通過KD樹進行距離最近點實現查找

發布時間:2021-07-22 14:59:55 來源:億速云 閱讀:174 作者:小新 欄目:編程語言

這篇文章主要為大家展示了“C#如何通過KD樹進行距離最近點實現查找”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“C#如何通過KD樹進行距離最近點實現查找”這篇文章吧。

1. KD樹介紹

Kd-Tree(KD樹),即K-dimensional tree,是一種高維索引樹形數據結構,常用于在大規模的高維數據空間進行最鄰近查找和近似最鄰近查找。我實現的KD樹是二維的Kd - tree。目的是在點集中尋找最近點。參考資料是Kd-Tree的百度百科。并且根據百度百科的邏輯組織了代碼。

2. KD樹的數學解釋

3. KD樹的構造方法

這里是用的二維點集進行構造Kd-tree。三維的與此類似。
樹中每個節點的數據類型:

public class KDTreeNode
  {
    /// <summary>
    /// 分裂點
    /// </summary>
    public Point DivisionPoint { get; set; }

    /// <summary>
    /// 分裂類型
    /// </summary>
    public EnumDivisionType DivisionType { get; set; }

    /// <summary>
    /// 左子節點
    /// </summary>
    public KDTreeNode LeftChild { get; set; }

    /// <summary>
    /// 右子節點
    /// </summary>
    public KDTreeNode RightChild { get; set; }
  }

3.1 KD樹構造邏輯流程

  • 將所有的點放入集合a中

  • 對集合所有點的X坐標求得方差xv,Y坐標求得方差yv

  • 如果xv > yv,則對集合a根據X坐標進行排序。如果 yv > xv,則對集合a根據y坐標進行排序。

  • 得到排序后a集合的中位數m。則以m為斷點,將[0,m-2]索引的點放到a1集合中。將[m,a.count]索引的點放到a2的集合中(m點的索引為m-1)。

  • 構建節點,節點的值為a[m-1],如果操作集合中節點的個數大于1,則左節點對[0,m-2]重復2-5步,右節點為對[m,a.count]重復2-5步;反之,則該節點為葉子節點。

3.2 代碼實現

private KDTreeNode CreateTreeNode(List<Point> pointList)
{
  if (pointList.Count > 0)
  {
    // 計算方差
    double xObtainVariance = ObtainVariance(CreateXList(pointList));
    double yObtainVariance = ObtainVariance(CreateYList(pointList));

    // 根據方差確定分裂維度
    EnumDivisionType divisionType = SortListByXOrYVariances(xObtainVariance,    yObtainVariance, ref pointList);

    // 獲得中位數
    Point medianPoint = ObtainMedian(pointList);
    int medianIndex = pointList.Count / 2;

    // 構建節點
    KDTreeNode treeNode = new KDTreeNode()
    {
      DivisionPoint = medianPoint,
      DivisionType = divisionType,
      LeftChild = CreateTreeNode(pointList.Take(medianIndex).ToList()),
      RightChild = CreateTreeNode(pointList.Skip(medianIndex + 1).ToList())
    };
    return treeNode;
  }
  else
  {
    return null;
  }
}

4. KD樹搜索方法

Kd-Tree的總體搜索流程先根據普通的查找找到一個最近的葉子節點。但是這個葉子節點不一定是最近的點。再進行回溯的操作找到最近點。

4.1 KD樹搜索邏輯流程

  • 對于根據點集構建的樹t,以及查找點p.將根節點作為節點t進行如下的操作

  • 如果t為葉子節點。則得到最近點n的值為t的分裂點的值,跳到第5步;如果t不是葉子節點,進行第3步

  • 則確定t的分裂方式,如果是按照x軸進行分裂,則用p的x值與節點的分裂點的x值進行比較,反之則進行Y坐標的比較

  • 如果p的比較值小于t的比較值,則將t指定為t的左孩子節點。反之將t指定為t的右孩子節點,執行第2步

  • 定義檢索點m,將m設置為n

  • 計算m與p的距離d1,n與m的距離d2。

  • 如果d1 >= d2且有父節點,則將m的父節點作為m的值執行5步,若沒有父節點,則得到真正的最近點TN; 如果d1 < d2就表示n點不是最近點,執行第8步

  • 若n有兄弟節點,則 n = n的兄弟節點;若n沒有兄弟節點,則 n = n的父節點。刪除原來的n節點。將m的值設置為新的n節點;執行第6步。

4.2 代碼實現

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)
  {
    // 利用堆棧記錄查詢的路徑,由于樹節點中沒有記載父節點的原因
    backtrackStack.Push(node);
  }
  if (node.DivisionType == EnumDivisionType.X)
  {
    return DFSXsearch(node,searchPoint);
  }
  else
  {
    return DFSYsearch(node, searchPoint);
  }
}

private Point BacktrcakSearch(Point searchPoint,Point nearestPoint)
{
  // 如果記錄路徑的堆棧為空則表示已經回溯到根節點,則查到的最近點就是真正的最近點
  if (backtrackStack.IsEmpty())
  {
    return nearestPoint;
  }
  else
  {
    KDTreeNode trackNode = backtrackStack.Pop();
    
    // 分別求回溯點與最近點距查找點的距離
    double backtrackDistance = ObtainDistanFromTwoPoint(searchPoint,     trackNode.DivisionPoint);
    double nearestPointDistance = ObtainDistanFromTwoPoint(searchPoint, nearestPoint);
    
    if (backtrackDistance < nearestPointDistance)
    {
      // 深拷貝節點的目的是為了避免損壞樹
      KDTreeNode searchNode = new KDTreeNode()
      {
        DivisionPoint = trackNode.DivisionPoint,
        DivisionType = trackNode.DivisionType,
        LeftChild = trackNode.LeftChild,
        RightChild = trackNode.RightChild
      };
      nearestPoint = DFSBackTrackingSearch(searchNode, searchPoint);
   }
   // 遞歸到根節點
   return BacktrcakSearch(searchPoint, nearestPoint);
  }
}

以上是“C#如何通過KD樹進行距離最近點實現查找”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

米泉市| 兴山县| 英吉沙县| 金门县| 大荔县| 富川| 郸城县| 渭南市| 陇西县| 巴彦淖尔市| 庆城县| 富源县| 紫云| 玛纳斯县| 剑河县| 恩平市| 无锡市| 突泉县| 波密县| 兴仁县| 蒲江县| 高阳县| 恩平市| 剑川县| 呼伦贝尔市| 八宿县| 板桥市| 马山县| 鄂伦春自治旗| 开平市| 扶风县| 东光县| 双柏县| 玛多县| 武乡县| 鹤山市| 遂昌县| 玉山县| 敦化市| 岳阳县| 河西区|