KD树+BBF+KNN使用C#实现(3)

        前面讲解了KD树的实现以及在KD树的基础之上进行的最近近邻查找,但是KD树上的最近邻查找有一个问题,在我系列中第一篇的提到的参考文章中就讲到KD树搜索最近邻节点的问题。在进行回溯查找的过程是一直到根节点才结束,并且还对一些不必要的节点进行了计算,这在多维空间中查找的时候,将面对效率下降的问题。针对这么问题就提出了BBF改进算法,实在KD树最近邻搜索算法的基础之上进行的改进算法。他加入了优先队列,在形成搜索路径的同时也形成了优先队列,在回溯查找的过程主要按照优先队列来进行查找,从而避免了重复路径的搜索过程。这个优先的队列的形成过程,有很多实现方法,如大顶堆,通过维护一个大顶堆,在回溯的过程中,总是从这个优先级队列中取优先级最高的进行回溯。这个优先级的定义是目标点与搜索点在分割维度方向上的距离,这个距离通常来说都是取绝对值的。

在我的实现过程,没有使用大顶堆来实现优先队列,主要使用的Lis数据的Insert()方法,每次在插入的时候就遍历优先队列,找到合适的位置后插入队列即可。

下面是BBF算法的代码:

1、优先队列的维护代码

#region 优先队列的添加和删除
        private void InsertPriorityList(Node node, float priority)
        {
            PriorityList pl = new PriorityList() { node = node, priority = priority };
            if (priorityList.Count==0)
            {
                priorityList.Insert(0, pl);
                return;
            }

            for (int i = 0; i < priorityList.Count; i++)
            {
                if (priorityList[i].priority >= priority)
                {
                    priorityList.Insert(i, pl);
                    break;
                }
            }
        }

        private void RmovePriority(Node node)
        {
            foreach (var tmp in priorityList)
            {
                if (tmp.node == node)
                {
                    priorityList.Remove(tmp);
                    break;
                }
            }
        }
        #endregion
2、优先级的计算

private float CalPriority(Node node, Train target,int split)
        {
            //计算目标点和分割点之间的距离,即优先级
            if (split == 0)
            {
                return Math.Abs(target.positionX - node.point.positionX);
            }
            else if (split == 1)
            {
                return Math.Abs(target.positionY - node.point.positionY);
            }
            else
                return Math.Abs(target.positionZ - node.point.positionZ);
        }
3、BBF算法

private Node BBFFindNearest(Node tree, Train target)
        {
            Node nearest = new Node();        //最近邻节点
            nearest = tree;

            float priority = -1; //优先级
            //计算优先级
            priority = this.CalPriority(nearest, target,tree.split);
            this.InsertPriorityList(nearest, priority);     //将根节点加入优先队列中

            Node topNode = null;    //优先级最高的节点
            Node currentNode=null;
            double dist = 0;
            while (priorityList.Count > 0)
            {
                topNode = priorityList[0].node; //优先队列中的第一个总是优先级最高的
                this.RmovePriority(topNode);

                while (topNode != null)
                {
                    //当前节点不是叶子节点
                    if (topNode.leftNode != null || topNode.righNode != null)
                    {
                        int split = topNode.split;
                        if (split == 0)
                        {
                            if (target.positionX <= topNode.point.positionX)
                            {
                                //current = topNode.point;
                                //若右节点不为空,将右子树节点添加到优先队列中
                                if (topNode.righNode!=null)
                                {
                                    priority = this.CalPriority(topNode.righNode, target, split);
                                    this.InsertPriorityList(topNode.righNode, priority);
                                }                               

                                topNode = topNode.leftNode;
                            }
                            else
                            {
                                //current = topNode.point;
                                //将左子树节点添加到优先级队列中
                                if (topNode.leftNode!=null)
                                {
                                    priority = this.CalPriority(topNode.leftNode, target, split);
                                    this.InsertPriorityList(topNode.leftNode, priority);
                                }                                

                                topNode = topNode.righNode;
                            }

                            currentNode = topNode;
                        }
                        else if (split == 1)
                        {
                            if (target.positionY <= topNode.point.positionY)
                            {
                                //current = topNode.point;
                                //将右子树节点添加到优先队列中
                                if (topNode.righNode!=null)
                                {
                                    priority = this.CalPriority(topNode.righNode, target, split);
                                    this.InsertPriorityList(topNode.righNode, priority);
                                }                                

                                topNode = topNode.leftNode;
                            }
                            else
                            {
                                //current = topNode.point;
                                //将左子树节点添加到优先级队列中
                                if (topNode.leftNode!=null)
                                {
                                    priority = this.CalPriority(topNode.leftNode, target, split);
                                    this.InsertPriorityList(topNode.leftNode, priority);
                                }                                

                                topNode = topNode.righNode;
                            }

                            currentNode = topNode;
                        }
                        else
                        {
                            if (target.positionZ <= topNode.point.positionZ)
                            {
                                //current = topNode.point;
                                //将右子树节点添加到优先队列中
                                if (topNode.righNode!=null)
                                {
                                    priority = this.CalPriority(topNode.righNode, target, split);
                                    this.InsertPriorityList(topNode.righNode, priority);
                                }                                

                                topNode = topNode.leftNode;
                            }
                            else
                            {
                                //current = topNode.point;
                                //将左子树节点添加到优先级队列中
                                if (topNode.leftNode!=null)
                                {
                                    priority = this.CalPriority(topNode.leftNode, target, split);
                                    this.InsertPriorityList(topNode.leftNode, priority);
                                }                                

                                topNode = topNode.righNode;
                            }
                            currentNode = topNode;
                        }
                    }
                    else
                    {
                        currentNode = topNode;
                        topNode = null;     //叶子节点
                    }

                    if (currentNode!=null && Distance(nearest.point,target)>Distance(currentNode.point,target))
                    {
                        nearest = currentNode;
                        dist = Distance(currentNode.point, target);
                    }
                }
            }
            return nearest;
        }
注:其中用的计算节点之间的距离函数Distance();这里计算的是欧几里德距离。

private double Distance(Train trainFirst, Train trainSecond)
        {
            double tmp = double.MaxValue;     //初始化节点间距离为无穷大
            tmp = Math.Sqrt(Math.Pow(trainFirst.positionX - trainSecond.positionX, 2) +
                            Math.Pow(trainFirst.positionY - trainSecond.positionY, 2) +
                            Math.Pow(trainFirst.positionZ - trainSecond.positionZ, 2));

            return tmp;
        }
BBF搜索算法结束。

暂时告一段落,虽然后面还有K近邻算法,那是在BBF的基础之上进行的改进,只需要在添加一个队列,主要存放的就是找到的临近点,在这个队列中,对找到的近邻节点进行排序,K近邻就是前K个节点。K近邻的实现参考文档中有实现,大家可以去研究一下即可,有时间我也会实现一下K近邻搜索的实现部分。

代码下载

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踏雪_无痕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值