我试图编写一个排序和扫描宽相系统,并且在重叠报告阶段我遇到了一些性能问题。
我的配对报告代码是瓶颈所在:
基本的想法是为每个轴生成一个重叠对的临时列表,然后对于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];
}
}
我读过的有关排序和扫描/扫描和修剪的材料并没有详细说明快速搜索重复对的方法,或者实际上是一种有效地搜索其他轴以获得等效对的方法方式。我显然遗漏了一些东西,所以我很感激能给予的任何帮助。
答案 0 :(得分:1)
考虑到这种算法明显的二次复杂性,性能问题在这里并不让我感到惊讶。
getId()
返回的是什么类或POD尚不清楚。为了清楚起见,我们假设getId()
返回IdType
类,mxExtents
是ExtentsType
类的容器。
如果IdType
实现了严格的弱排序(这意味着它实现了operator<
,除了operator==
),并且您相信如果{{1}的数量,您将获得更好的性能返回比较,然后我建议创建一个
IdType
现在通过对 std::multimap<IdType, ExtentsType *> lookup;
进行一次传递填充lookup
,将每个值的mxExtents
和指向原始IdType
实例的指针插入到多图中。插入操作将具有对数复杂度,然后在插入所有内容之后,对multimap容器进行单次传递将使得ExtentsType
的所有ExtentsType
实例具有相同的IdType
变得微不足道。由于原始插入操作具有对数复杂度,我预计第一遍的比较总数将会少得多。
当然,第二遍将具有线性复杂性,但这对我来说就像是最容易尝试的最简单的结果,看看这是否能解决你的疑似瓶颈问题。
另一个可能的变化是使用std::multiset
而不是std::multimap
,使用自定义比较器类。这样就可以根据每个ExtentsType
与其内部IdType
实例之间的内部关系采用一些额外的优化,以消除此处发生的许多内部复制/移动结构。其中继承了原始算法的二次复杂度(并且通过切换到多图,并且可能通过使用自定义多集比较器完全消除,也会相应减少)。