我的代码中有一个泛洪填充功能,它只返回填充单元格上的数字。但它的速度极慢,我的A *寻路算法比它快得多。这是片段:
bool withinBoundaries(_2D::Point p) {
//cerr << "Checking if x: " << p.x << " y: " << p.y << " is within boundaries" << endl;
if (p.x <= 29 && p.y <= 19 && p.x >= 0 && p.y >= 0) {
return true;
}
return false;
}
bool canMove(_2D::Point point, _2D::Point offset, map<pair<int, int>, bool> gameGrid) {
if (!gameGrid[(point + offset).toPair()] && withinBoundaries(point + offset)) return true;
else return false;
}
int floodFillGetArea(_2D::Point point, map<pair<int, int>, bool> gameGrid) {
map<pair<int, int>, bool> checked;
map<pair<int, int>, bool> gameGridCopy = gameGrid;
deque<_2D::Point> openPoints;
openPoints.push_back(point);
int count = 0;
while (!openPoints.empty()) {
_2D::Point curPoint = openPoints.back();
openPoints.pop_back();
if(checked[curPoint.toPair()]) break;
gameGridCopy[curPoint.toPair()] = true;
count++;
if (canMove(curPoint, _2D::Point::UP(), gameGridCopy)) {
openPoints.push_back(curPoint + _2D::Point::UP());
}
if (canMove(curPoint, _2D::Point::RIGHT(), gameGridCopy)) {
openPoints.push_back(curPoint + _2D::Point::RIGHT());
}
if (canMove(curPoint, _2D::Point::DOWN(), gameGridCopy)) {
openPoints.push_back(curPoint + _2D::Point::DOWN());
}
if (canMove(curPoint, _2D::Point::LEFT(), gameGridCopy)) {
openPoints.push_back(curPoint + _2D::Point::LEFT());
}
checked[curPoint.toPair()] = true;
}
return count;
}
这会每秒检查一个节点,为什么这么慢? _2D :: Point只是一个int x和int y的对象。当它们已被标记为被检查时,它会创建开放的点头,为什么?
答案 0 :(得分:3)
对于初学者,您无需复制std::map
个对象6次。
尝试将地图对象作为const引用传递,而不是通过值(= copy)
传递它答案 1 :(得分:1)
你可以尝试使用一组二维布尔而不是一个地图(需要O(log N)操作来查找)&#34; gameGrid&#34;宾语?如果数组不是一个选项,切换到哈希表可能会提供类似的性能吗?
如果地图中有1024个点,则应将基准速度乘以10-11。
如果这还不够,你可以有多个线程和多个阶段(同步)来计算1,4,16,20,20,20,16,4,1,1,4,16,2,4。 ..瓷砖,一次完成。
在阵列上尝试这样的事情(扫描线填充?):
while(canMove(right)){enqueue} // Sequential memory access
reset horizontal pos, enable reverse prefetching
while(canMove(left)){enqueue} // Sequential memory access
....
then repeat for verticals
然后用交替的水平+垂直计算重复直到完成。这个模式应该给出x2内存性能乘数,并且最重要的是10-11x数组访问时序升级,因为它不会从内存访问结构(对),只是一个字节。
另一种方式,您也可以在随机位置启动多个填充点并迭代,直到其中一个接触原始洪水,将其点添加到原始点区域,将其所有工作移动到原始floot线程,最后释放所有不接触洪水。这可能会更频繁地使用缓存吗?但它需要更多核心。尝试gpgpu版本也不会受到伤害。
注意:这将隐式强制执行@David Haim建议的另一个优化。通过所有这些优化,您必须看到您提到的有关A *算法的指数加速。