zoukankan      html  css  js  c++  java
  • KDTree  C++实现

    参考:https://blog.csdn.net/qing101hua/article/details/53228668

    #include <iostream>
    #include <vector>
    #include <stack>
    #include <cmath>
    
    #define KDtreeSize 1000
    
    #define UL unsigned long
    
    using namespace std;
    
    
    struct coordinate
    {
        double x = 0;
        double y = 0;
        UL index = 0;
    };
    
    struct TreeNode
    {
        struct coordinate dom_elt;
        UL split = 0;
        struct TreeNode* left = nullptr;
        struct TreeNode* right = nullptr;
    };
    
    bool cmp1(const coordinate& a, const coordinate& b){
        return a.x < b.x;
    }
    
    bool cmp2(const coordinate& a, const coordinate& b){
        return a.y < b.y;
    }
    
    bool equal(const coordinate& a, const coordinate& b){
        return (a.x == b.x && a.y == b.y);
    }
    
    void ChooseSplit(coordinate exm_set[], UL size, UL &split, coordinate &SplitChoice){
        /*compute the variance on every dimension. Set split as the dismension that have the biggest
         variance. Then choose the instance which is the median on this split dimension.*/
        /*compute variance on the x,y dimension. DX=EX^2-(EX)^2*/
        double tmp1, tmp2;
        tmp1 = tmp2 = 0;
        for (int i = 0; i < size; ++i)
        {
            tmp1 += 1.0 / (double)size * exm_set[i].x * exm_set[i].x;
            tmp2 += 1.0 / (double)size * exm_set[i].x;
        }
        double v1 = tmp1 - tmp2 * tmp2;  //compute variance on the x dimension
    
        tmp1 = tmp2 = 0;
        for (int i = 0; i < size; ++i)
        {
            tmp1 += 1.0 / (double)size * exm_set[i].y * exm_set[i].y;
            tmp2 += 1.0 / (double)size * exm_set[i].y;
        }
        double v2 = tmp1 - tmp2 * tmp2;  //compute variance on the y dimension
    
        split = v1 > v2 ? 0:1; //set the split dimension
    
        if (split == 0)
        {
            sort(exm_set,exm_set + size, cmp1);
        }
        else{
            sort(exm_set,exm_set + size, cmp2);
        }
    
        //set the split point value
        SplitChoice.x = exm_set[size / 2].x;
        SplitChoice.y = exm_set[size / 2].y;
    
    }
    
    
    TreeNode* build_kdtree(coordinate exm_set[], UL size, TreeNode* T){
        //call function ChooseSplit to choose the split dimension and split point
        if (size == 0){
            return nullptr;
        }
        else{
            UL split;
            coordinate dom_elt;
            ChooseSplit(exm_set, size, split, dom_elt);
            coordinate exm_set_right [KDtreeSize];
            coordinate exm_set_left [KDtreeSize];
            UL size_left ,size_right;
            size_left = size_right = 0;
    
            if (split == 0)
            {
                for (UL i = 0; i < size; ++i)
                {
    
                    if (!equal(exm_set[i],dom_elt) && exm_set[i].x <= dom_elt.x)
                    {
                        exm_set_left[size_left].x = exm_set[i].x;
                        exm_set_left[size_left].y = exm_set[i].y;
                        size_left++;
                    }
                    else if (!equal(exm_set[i],dom_elt) && exm_set[i].x > dom_elt.x)
                    {
                        exm_set_right[size_right].x = exm_set[i].x;
                        exm_set_right[size_right].y = exm_set[i].y;
                        size_right++;
                    }
                }
            }
            else{
                for (UL i = 0; i < size; ++i)
                {
    
                    if (!equal(exm_set[i],dom_elt) && exm_set[i].y <= dom_elt.y)
                    {
                        exm_set_left[size_left].x = exm_set[i].x;
                        exm_set_left[size_left].y = exm_set[i].y;
                        size_left++;
                    }
                    else if (!equal(exm_set[i],dom_elt) && exm_set[i].y > dom_elt.y)
                    {
                        exm_set_right[size_right].x = exm_set[i].x;
                        exm_set_right[size_right].y = exm_set[i].y;
                        size_right++;
                    }
                }
            }
            T = new TreeNode;
            T->dom_elt.x = dom_elt.x;
            T->dom_elt.y = dom_elt.y;
            T->split = split;
            T->left = build_kdtree(exm_set_left, size_left, T->left);
            T->right = build_kdtree(exm_set_right, size_right, T->right);
            return T;
    
        }
    }
    
    
    double Distance(coordinate a, coordinate b){
        double tmp = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
        return sqrt(tmp);
    }
    
    
    void searchNearest(TreeNode * Kd, coordinate target, coordinate &nearestpoint, double & distance){
    
        //1. 如果Kd是空的,则设dist为无穷大返回
    
        //2. 向下搜索直到叶子结点
    
        stack<TreeNode*> search_path;
        TreeNode* pSearch = Kd;
        coordinate nearest;
        double dist;
    
        while(pSearch != nullptr)
        {
            //pSearch加入到search_path中;
            search_path.push(pSearch);
    
            if (pSearch->split == 0)
            {
                if(target.x <= pSearch->dom_elt.x) /* 如果小于就进入左子树 */
                {
                    pSearch = pSearch->left;
                }
                else
                {
                    pSearch = pSearch->right;
                }
            }
            else{
                if(target.y <= pSearch->dom_elt.y) /* 如果小于就进入左子树 */
                {
                    pSearch = pSearch->left;
                }
                else
                {
                    pSearch = pSearch->right;
                }
            }
        }
        //取出search_path最后一个赋给nearest
        nearest.x = search_path.top()->dom_elt.x;
        nearest.y = search_path.top()->dom_elt.y;
        search_path.pop();
    
    
        dist = Distance(nearest, target);
        //3. 回溯搜索路径
    
        TreeNode* pBack;
    
        while(search_path.empty())
        {
            //取出search_path最后一个结点赋给pBack
            pBack = search_path.top();
            search_path.pop();
    
            if(pBack->left == nullptr && pBack->right == nullptr) /* 如果pBack为叶子结点 */
    
            {
    
                if( Distance(nearest, target) > Distance(pBack->dom_elt, target) )
                {
                    nearest = pBack->dom_elt;
                    dist = Distance(pBack->dom_elt, target);
                }
    
            }
    
            else
    
            {
    
                UL s = pBack->split;
                if (s == 0)
                {
                    if( fabs(pBack->dom_elt.x - target.x) < dist) /* 如果以target为中心的圆(球或超球),半径为dist的圆与分割超平面相交, 那么就要跳到另一边的子空间去搜索 */
                    {
                        if( Distance(nearest, target) > Distance(pBack->dom_elt, target) )
                        {
                            nearest = pBack->dom_elt;
                            dist = Distance(pBack->dom_elt, target);
                        }
                        if(target.x <= pBack->dom_elt.x) /* 如果target位于pBack的左子空间,那么就要跳到右子空间去搜索 */
                            pSearch = pBack->right;
                        else
                            pSearch = pBack->left; /* 如果target位于pBack的右子空间,那么就要跳到左子空间去搜索 */
                        if(pSearch != nullptr)
                            //pSearch加入到search_path中
                            search_path.push(pSearch);
                    }
                }
                else {
                    if( fabs(pBack->dom_elt.y - target.y) < dist) /* 如果以target为中心的圆(球或超球),半径为dist的圆与分割超平面相交, 那么就要跳到另一边的子空间去搜索 */
                    {
                        if( Distance(nearest, target) > Distance(pBack->dom_elt, target) )
                        {
                            nearest = pBack->dom_elt;
                            dist = Distance(pBack->dom_elt, target);
                        }
                        if(target.y <= pBack->dom_elt.y) /* 如果target位于pBack的左子空间,那么就要跳到右子空间去搜索 */
                            pSearch = pBack->right;
                        else
                            pSearch = pBack->left; /* 如果target位于pBack的右子空间,那么就要跳到左子空间去搜索 */
                        if(pSearch != nullptr)
                            // pSearch加入到search_path中
                            search_path.push(pSearch);
                    }
                }
    
            }
        }
    
        nearestpoint.x = nearest.x;
        nearestpoint.y = nearest.y;
        distance = dist;
    
    }
    
    
    
    void test_kdtree(){
        coordinate exm_set[6];
        exm_set[0].x = 2;    exm_set[0].y = 3;
        exm_set[1].x = 5;    exm_set[1].y = 4;
        exm_set[2].x = 9;    exm_set[2].y = 6;
        exm_set[3].x = 4;    exm_set[3].y = 7;
        exm_set[4].x = 8;    exm_set[4].y = 1;
        exm_set[5].x = 7;    exm_set[5].y = 2;
    
        struct TreeNode * root = nullptr;
        root = build_kdtree(exm_set, 6, root);
    
        coordinate nearestpoint;
        double distance;
        coordinate target;
        target.x = 2.1;
        target.y = 3.2;
    
        searchNearest(root, target, nearestpoint, distance);
        cout<<"The nearest distance is "<<distance<<",and the nearest point is "<<nearestpoint.x<<","<<nearestpoint.y<<endl;
    }
    
    
    int main(){
        test_kdtree();
        return 0;
    }
    
  • 相关阅读:
    21.Merge Two Sorted Lists 、23. Merge k Sorted Lists
    34. Find First and Last Position of Element in Sorted Array
    leetcode 20. Valid Parentheses 、32. Longest Valid Parentheses 、301. Remove Invalid Parentheses
    31. Next Permutation
    17. Letter Combinations of a Phone Number
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项
    oc 异常处理
    oc 类型判断
    oc Delegate
    oc 协议
  • 原文地址:https://www.cnblogs.com/theodoric008/p/9475189.html
Copyright © 2011-2022 走看看