排序和扫描对报告中的性能问题

时间:2016-01-15 12:03:47

标签: c++ algorithm broad-phase

我试图编写一个排序和扫描宽相系统,并且在重叠报告阶段我遇到了一些性能问题。

我的配对报告代码是瓶颈所在:

基本的想法是为每个轴生成一个重叠对的临时列表,然后对于X中的每一对,检查该对是否存在于Y和Z中。在生成对中进行一些额外的检查以处理堆叠立方体和遏制边缘情况。 对生成代码如下:

//temporary pair generation for X axis
for (unsigned int i = 0; i < mXExtents.size()-1; i++)
{
    if (!mXExtents[i].mMax)
    {
        for (unsigned int j = i + 1; j < mXExtents.size(); j++)
        {
            if (mXExtents[j].mOwner->getID() == mXExtents[i].mOwner->getID())
            {
                break;
            }
            else
            {
                tempXPairs.push_back(new Pair(mXExtents[i].mOwner, mXExtents[j].mOwner));
            }
        }
    }
}
//temporary pair generation for Y axis
for (unsigned int i = 0; i < mYExtents.size()-1; i ++)
{
    if (!mYExtents[i].mMax)
    {
        for (unsigned int j = i + 1; j < mYExtents.size(); j++)
        {
            if (mYExtents[j].mOwner->getID() == mYExtents[i].mOwner->getID())
            {
                break;
            }
            else
            {
                tempYPairs.push_back(new Pair(mYExtents[i].mOwner, mYExtents[j].mOwner));
            }
        }
    }
}
//temporary pair generation for Z axis
for (unsigned int i = 0; i < mZExtents.size()-1; i ++)
{
    if (!mZExtents[i].mMax)
    {
        for (unsigned int j = i + 1; j < mZExtents.size(); j++)
        {
            if (mZExtents[j].mOwner->getID() == mZExtents[i].mOwner->getID())
            {
                break;
            }
            else
            {
                tempZPairs.push_back(new Pair(mZExtents[i].mOwner, mZExtents[j].mOwner));
            }
        }
    }
}

通过分析找到的瓶颈是在通过==运算符比较对时发生的。我怀疑这是由于执行了许多这样的检查,而不是检查本身的开销。

配对报告代码如下:

    bool found = false;
    //now search Y & Z temp storage for matching pairs
    for (unsigned int i = 0; i < tempXPairs.size(); i++)
    {
        if (tempXPairs[i] != nullptr)
        {
            //search Y first
            for (unsigned int j = 0; j < tempYPairs.size(); j++)
            {
                if (tempYPairs[j] != nullptr)
                {
                    //match found in Y
                    if (*tempXPairs[i] == *tempYPairs[j])
                    {
                        //make a quick copy and stop searching
                        found = true;
                        delete tempYPairs[j];
                        tempYPairs[j] = nullptr;
                        break;
                    }
                }
            }
            //element in Y found
            if (found)
            {
                found = false;
                //search Z temp list for a match
                for (unsigned int j = 0; j < tempZPairs.size(); j++)
                {
                    if (tempZPairs[j] == nullptr)
                        continue;
                    //match in Z found
                    if (*tempXPairs[i] == *tempZPairs[j])
                    {
                        //if we are at this stage then we have a triple match, so an overlap on all axes.
                        //add the pair to the manager
                        mPairManager->addpair(tempXPairs[i]);
                        //delete extranious pairs
                        delete tempZPairs[j];
                        tempZPairs[j] = nullptr;
                        //clear variables 
                        tempXPairs[i] = nullptr;
                        //and end search
                        break;
                    }

                }
                //not found so get rid of all relevant pairs and move on to next in X list
                delete tempXPairs[i];
                tempXPairs[i] = nullptr;
            }
            else
            {
                delete tempXPairs[i];
                tempXPairs[i] = nullptr;
            }
        }
    }
    //finally clear temp storage
    for (unsigned int i = 0; i < tempXPairs.size(); i++)
    {
        if (tempXPairs[i] != nullptr)
        {
            delete tempXPairs[i];
        }
    }
    for (unsigned int i = 0; i < tempYPairs.size(); i++)
    {
        if (tempYPairs[i] != nullptr)
        {
            delete tempYPairs[i];
        }
    }
    for (unsigned int i = 0; i < tempZPairs.size(); i++)
    {
        if (tempZPairs[i] != nullptr)
        {
            delete tempZPairs[i];
        }
    }

我读过的有关排序和扫描/扫描和修剪的材料并没有详细说明快速搜索重复对的方法,或者实际上是一种有效地搜索其他轴以获得等效对的方法方式。我显然遗漏了一些东西,所以我很感激能给予的任何帮助。

1 个答案:

答案 0 :(得分:1)

考虑到这种算法明显的二次复杂性,性能问题在这里并不让我感到惊讶。

getId()返回的是什么类或POD尚不清楚。为了清楚起见,我们假设getId()返回IdType类,mxExtentsExtentsType类的容器。

如果IdType实现了严格的弱排序(这意味着它实现了operator<,除了operator==),并且您相信如果{{1}的数量,您将获得更好的性能返回比较,然后我建议创建一个

IdType

现在通过对 std::multimap<IdType, ExtentsType *> lookup; 进行一次传递填充lookup,将每个值的mxExtents和指向原始IdType实例的指针插入到多图中。插入操作将具有对数复杂度,然后在插入所有内容之后,对multimap容器进行单次传递将使得ExtentsType的所有ExtentsType实例具有相同的IdType变得微不足道。由于原始插入操作具有对数复杂度,我预计第一遍的比较总数将会少得多。

当然,第二遍将具有线性复杂性,但这对我来说就像是最容易尝试的最简单的结果,看看这是否能解决你的疑似瓶颈问题。

另一个可能的变化是使用std::multiset而不是std::multimap,使用自定义比较器类。这样就可以根据每个ExtentsType与其内部IdType实例之间的内部关系采用一些额外的优化,以消除此处发生的许多内部复制/移动结构。其中继承了原始算法的二次复杂度(并且通过切换到多图,并且可能通过使用自定义多集比较器完全消除,也会相应减少)。