Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使洪水填充算法更有效?_C++_Algorithm_Graph Algorithm_Flood Fill - Fatal编程技术网

C++ 如何使洪水填充算法更有效?

C++ 如何使洪水填充算法更有效?,c++,algorithm,graph-algorithm,flood-fill,C++,Algorithm,Graph Algorithm,Flood Fill,我的代码中有一个flood-fill函数,它只返回填充单元格上的一个数字。但是它的速度非常慢,我的A*寻路算法比它快了很多。以下是片段: bool withinBoundaries(_2D::Point p) { //cerr << "Checking if x: " << p.x << " y: " << p.y << " is within boundaries" << endl; if (p.x <= 29

我的代码中有一个flood-fill函数,它只返回填充单元格上的一个数字。但是它的速度非常慢,我的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的对象。当打开的节点已经标记为正在检查时,它还会创建打开的节点,为什么?

对于初学者,您可以免费复制std::map对象6次

尝试将映射对象作为const引用传递,而不是通过value=copy传递。对于初学者,可以免费复制std::map对象6次


尝试将map对象作为常量引用传递,而不是通过value=copy传递它。你能尝试使用一个2D布尔数组,而不是通过Olog N操作来查找gameGrid对象吗?如果数组不是一个选项,那么切换到哈希表可能会提供类似的性能

如果地图上有1024个点,这应该是基准速度乘以10-11

如果这还不够,您可以让多个线程和多个阶段进行同步,以计算1、4、16、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-11倍的阵列访问定时升级,因为它不会从内存访问结构对,只会访问一个字节

另一种方法是,您还可以在随机位置启动多个填充点,并进行迭代,直到其中一个点接触到原始泛洪,将其点添加到原始点区域,将其所有工作移动到原始floot线程,最后释放所有非接触泛洪。这可能会更频繁地使用缓存?但它需要更多的内核。同时尝试gpgpu版本也不会有什么坏处


注意:这将隐含地强制执行@David Haim建议的另一个优化。通过所有这些优化,您一定看到了您提到的A*算法的指数加速。

您可以尝试使用一个2D布尔数组,而不是一个需要Olog N操作来查找gameGrid对象的映射吗?如果数组不是一个选项,那么切换到哈希表可能会提供类似的性能

如果地图上有1024个点,这应该是基准速度乘以10-11

如果这还不够,您可以让多个线程和多个阶段进行同步,以计算1、4、16、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-11倍的阵列访问定时升级,因为它不会从内存访问结构对,只会访问一个字节

另一种方法是,您还可以在随机位置启动多个填充点,并进行迭代,直到其中一个点接触到原始泛洪,将其点添加到原始点区域,将其所有工作移动到原始floot线程,最后释放所有非接触泛洪。这可能会更频繁地使用缓存?但它需要更多的内核。同时尝试gpgpu版本也不会有什么坏处


注意:这将隐含地强制执行@David Haim建议的另一个优化。通过所有这些优化,您一定看到了您提到的关于A*算法的指数加速。

您通过gameGrid并通过复制而不是常量引用进行检查……我认为您将有更好的答案,gameGrid是静态的,这只是一个测试,只是函数操纵它来检查区域。也检查了应该是本地的我不知道为什么我把它作为一个函数,这是你真正的代码吗?如果检查[curPoint.toPair]断路;看起来很奇怪。是的,我的坐标结构有一个名为toPair的函数,因为maps dno不能很好地处理对象。你通过gameGrid并通过副本而不是常量引用进行检查……我想你会有更好的答案gameGrid是静态的,这只是一个测试,只是函数操纵它来检查区域。也检查了应该是本地的我不知道为什么我把它作为一个函数,这是你真正的代码吗?如果检查[curPoint.toPair]断路;看起来很奇怪。是的,我的坐标结构有一个名为toPair的函数,因为maps dno不能很好地处理对象。没有明显的差异,但技术上是的,它应该很快。你在发布模式下编译它时启用了优化?我在启用优化的情况下编译过它,但如果没有启用,它应该不会这么慢。我未经优化的A*寻路功能就像500个节点/毫秒+可视化一样,没有明显的差异,但技术上是的,它应该更快。你在发布模式下编译过它吗?我用optimiza编译过它
开着,但没有开着,就不会这么慢。我的非优化A*寻路功能就像500个节点/毫秒+可视化一样,遍历映射意味着以随机顺序访问RAM,而使用数组则是按顺序访问RAM。@GuyGreer,尤其是扫描线泛洪。同样遍历映射意味着以随机顺序访问RAM,而对于阵列,您是按顺序访问RAM。@GuyGreer,尤其是扫描线泛洪。