首页 > 其他分享 >性能提升-空间二叉查找树

性能提升-空间二叉查找树

时间:2023-08-06 18:55:07浏览次数:34  
标签:const 性能 Tree Standard 查找 二叉树 二叉

性能提升-空间二叉查找树

[email protected]

Abstract.  OpenCASCADE provides NCollection_UBTree to achieve high performance search overlapped boxes. The algorithm of unbalanced binary tree of overlapped bounding boxes. Once the tree of boxes  of geometric objects is constructed, the algorithm is capable of fast geometric selection of objects.  The tree can be easily updated by adding to it a new object with bounding box. The time of adding to the tree  of one object is O(log(N)), where N is the total number of  objects, so the time  of building a tree of  N objects is O(N(log(N)). The search time of one object is O(log(N)). Defining  various classes  inheriting NCollection_UBTree::Selector  we can perform various kinds of selection over the same b-tree object.

Key Words. Unbalanced Binary Tree, Binary Search Tree, Binary Sort Tree, Bounding Box

1 Introduction

非平衡二叉树(Unbalanced Binary Tree)又叫二叉查找树(Binary Search Tree)或二叉排序树(Binary Sort Tree)。它的定义很简单,就是左子树上所有节点的值都要小于根节点上的值。右子树上所有节点值都要大于根节点上的值。在二叉查找树上执行操作时间与树的高度成正比。对于一棵含有n个结点的完全二叉树,这些操作的最坏情况运行时间为O(lg(n))。但是如果树是含n个结点的线性链,则这些操作的最坏的情况运行时间为O(n)。一棵随机构造的二叉查找树的期望高度为O(lg(n)),从而这种树上操作的平均时间为O(lg(n))。

几何搜索(geometry searching)大致分两类:一类是区域搜索问题(range searching problem),另一类是点的定位问题(point location problem)。区域搜索问题要回答的是给定一个区域,看有多少模型属于这个区域。当然,我们可以对所有模型进行遍历,这种算法时间复杂度为O(N),效率不高。常见的高效的区域搜索算法有k-D树,k-D树就是一种多维的平衡二叉树。还有比较常见的KNN问题,这些都是计算几何处理的问题。

OpenCASCADE中提供一种空间查找二叉树算法NCollection_UBTree,字面意思是非平衡二叉树Unbalanced Binary Tree。把上图中的数字换成包围盒,构造二叉查找树。为了解决查找二叉树单链问题,加入随机处理,可以使查找性能达到O(log(N)),相对普通遍历速度而言还是不错的。本文结合示例代码说明如何使用这个非平衡二叉树。

2 Example

在OpenCASCADE中有多个函数来实现将很多无序边Edges连接成Wire,需要查询一条边Edge的一个顶点Vertex在一定精度范围内相连的顶点Vertex有哪些?

首先,实现一个选择类,通过选择类来进行过滤:

typedef NCollection_UBTree<Standard_Integer, Bnd_Box> BoxTree;
typedef NCollection_UBTreeFiller<Standard_Integer, Bnd_Box> BoxTreeFiller;

class BoxSelector : public BoxTree::Selector
{
public:
    BoxSelector(const TColgp_SequenceOfPnt& thePoints, Standard_Real theTolerance)
        : Selector()
        , myPoints(thePoints)
        , myTolerance(theTolerance)
    {

    }

    virtual Standard_Boolean Reject(const Bnd_Box& theBox) const
    {
        return theBox.IsOut(myBox);
    }

    virtual Standard_Boolean Accept(const Standard_Integer& theIndex)
    {
        if (theIndex > myPoints.Size() || theIndex == myIndex)
        {
            return Standard_False;
        }

        const gp_Pnt& aPnt = myPoints.Value(theIndex);
        if (aPnt.SquareDistance(myPnt) < myTolerance)
        {
            myResultIndex.Append(theIndex);

            return Standard_True;
        }

        return Standard_False;
    }

    void SetCurrentPoint(const gp_Pnt& thePnt, Standard_Integer theIndex)
    {
        myPnt = thePnt;
        myBox.Add(thePnt);
        myIndex = theIndex;
    }

    const TColStd_ListOfInteger& GetResultIndex() const
    {
        return myResultIndex;
    }

    void ClearResultIndex()
    {
        myResultIndex.Clear();
    }

protected:

private:
    const TColgp_SequenceOfPnt& myPoints;

    gp_Pnt myPnt;

    Bnd_Box myBox;

    Standard_Integer myIndex;

    Standard_Real myTolerance;

    TColStd_ListOfInteger myResultIndex;
};

主要实现两个抽象函数Reject()和Accept(),以及设置当前选择器的状态。Reject()函数用来判断要查找的Box与当前空间范围的状态,如果在外,则返回True。当两个Box有相交时,会调用Accept()函数,在此函数中判断两个点的距离是否在容差范围内,若在容差范围内,则将点记录起来。主函数main代码如下:

int main(int argc, char* argv[])
{
    // Fill tree with random points.
    BoxTree aBoxTree;
    BoxTreeFiller aTreeFiler(aBoxTree);

    math_BullardGenerator aRandom;

    TColgp_SequenceOfPnt aPoints;

    for (Standard_Integer i = 1; i <= 100; ++i)
    {
        gp_Pnt aPnt(aRandom.NextReal(), aRandom.NextReal(), aRandom.NextReal());

        aPoints.Append(aPnt);

        Bnd_Box aBox;
        aBox.Add(aPnt);

        aTreeFiler.Add(i, aBox);
    }

    aTreeFiler.Fill();

    // Query points near the given point.
    BoxSelector aSelector(aPoints, 0.1);

    for (Standard_Integer i = aPoints.Lower(); i <= aPoints.Upper(); ++i)
    {
        const gp_Pnt& aPnt = aPoints.Value(i);

        aSelector.SetCurrentPoint(aPnt, i);

        Standard_Integer aSize = aBoxTree.Select(aSelector);
        if (aSize > 0)
        {
            std::cout << "Search Point : " << aPnt.X() << " \t " << aPnt.Y() << " \t " << aPnt.Z() << std::endl;
            const TColStd_ListOfInteger& aResult = aSelector.GetResultIndex();
            for (TColStd_ListOfInteger::Iterator aIt(aResult); aIt.More(); aIt.Next())
            {
                const gp_Pnt& aPoint = aPoints.Value(aIt.Value());
                std::cout << "Target Point : " << aPoint.X() << " \t " << aPoint.Y() << " \t " << aPoint.Z() << std::endl;
            }

            std::cout << "=============================" << std::endl;
        }

        aSelector.ClearResultIndex();
    }

    return 0;
}

先用随机函数随机生成100个点,并将点通过BoxTreeFiller添加到查找树aBoxTree中,调用Fill函数构造查找树。

再使用类BoxSelector来进行快速查找,查找之前先设置当前点及包围盒。然后调用aBoxTree.Select(aSelector)进行查找。

3 Conclusion

类NCollection_UBTree通过构造包围盒的非平衡二叉树来加快区域搜索速度。如何提高搜索速度,是计算几何处理的范畴。在OpenCASCADE中这个类使用场景比较多,如将无序边构造成Wire时都用这个类:BRepLib_MakeWire::Add(const TopTools_ListOfShape& L), ShapeAnalysis_FreeBounds::ConnectEdgesToWires()。包括后面引入的BVH都是为了提高搜索速度,在合适的场景中多使用这些算法,会对程序性能的提升有很大帮助。

 

标签:const,性能,Tree,Standard,查找,二叉树,二叉
From: https://www.cnblogs.com/opencascade/p/NCollection_UBTree.html

相关文章

  • 性能优化:如何定位耗时区域
    对一个系统的量化工作越深入,掌握的关键数字越多,意味着对这个系统的认识也就越深入。引子随着系统功能的不断垒积,系统运行会变慢,甚至慢得难以忍受,用户会强烈吐槽,这时候,就需要性能优化了。要做性能优化,首要的就是先定位耗时区域。耗时区域也成为“热点”。不做热点定位的性能......
  • 使用缓存优化网站性能:缓解数据库压力,提高访问速度
    使用缓存是一种有效的优化网站性能的方式,特别是对于那些访问集中在少部分数据上的场景,可以显著减轻数据库的压力,提高网站的响应速度和性能。缓存的主要原理是将常用的数据存储在内存中,以避免频繁地从数据库读取数据。由于内存的读写速度远远快于磁盘,通过缓存可以大幅提高数据访问......
  • 剑指 Offer 32 - I. 从上到下打印二叉树(中等)
    题目://考察BFS(广度优先搜索)classSolution{public:vector<int>levelOrder(TreeNode*root){if(root==nullptr)return{};//一定不要漏了排除空树的情况vector<int>result;deque<TreeNode*>que;//用一个队列,利......
  • 如何使用 Python 运算符进行性能优化 All In One
    如何使用Python运算符进行性能优化AllInOne为什么Python运算符//比运算符/性能更好,运行速度更快呀❓WhyPythonoperator//isfasterthanoperator/demosclassSolution:defnumberOfSteps(self,num:int)->int:steps:int=0whilenum>......
  • Android平台GB28181设备接入端如何降低资源占用和性能消耗
    背景我们在做GB28181设备接入模块的时候,考虑到好多设备性能一般,我们一般的设计思路是,先注册设备到平台侧,平台侧发calalog过来,获取设备信息,然后,设备侧和国标平台侧维持心跳,如果有位置订阅信息,按照订阅时间间隔,实时上报设备位置信息。如果本地没有录像诉求,或者,国标平台侧不发起invite......
  • dperf minio 团队开源的磁盘性能测试工具
    dperfminio团队开源的磁盘性能测试工具基于golang开发,使用简单,类似的有fio说明相比fiodperf没有那么多的参数,实际上dperf核心似乎主要是为了方便minio使用的,但是对于日常中需要测试一些磁盘问题也是可以的,可以用来发现磁盘的瓶颈参考资料https://github.com/minio/dpe......
  • 剑指 Offer 07. 重建二叉树
    classSolution{privateMap<Integer,Integer>indexMap;publicTreeNodemyBuildTree(int[]preorder,int[]inorder,intpreorder_left,intpreorder_right,intinorder_left,intinorder_right){if(preorder_left>preorder_right)......
  • 剑指 Offer 07. 重建二叉树
    输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 示例1:Input:preorder=[3,9,20,15,7],inorder=[9,3,15,20,7]Output:[3,9,20,null,null,15,7]示例2:Input:preorder=[-1],inorder=......
  • 剑指 Offer 07. 重建二叉树
    输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。示例1:Input:preorder=[3,9,20,15,7],inorder=[9,3,15,20,7]Output:[3,9,20,null,null,15,7]示例2:Input:preorder=[-1],inorder......
  • Cilium系列-13-启用XDP加速及Cilium性能调优总结
    系列文章Cilium系列文章前言将Kubernetes的CNI从其他组件切换为Cilium,已经可以有效地提升网络的性能.但是通过对Cilium不同模式的切换/功能的启用,可以进一步提升Cilium的网络性能.具体调优项包括不限于:启用本地路由(NativeRouting)完全替换KubeProxyI......