跳跃点搜索是否严格优于 A*?

Is Jump Point Search strictly better than A*?

根据很多相关资料,似乎Jump Point Search在满足要求条件(uniform-cost grid等)时严格优于A*

但是经过一些实际测试,我发现跳跃点搜索的搜索时间几乎与A*相同(甚至更糟......),我对此不太确定......(实现问题? 随机网格 ?)

搜索实现来自here,测试代码如下:

int profileCount = 256;
long elapsedJumpPoint = 0;
long elapsedAStar = 0;

for (int i = 0; i < profileCount; ++i)
{
    // random set obstacles here
    RandomizeGrid(searchGrid);

    {
        searchGrid.Reset();

        var stopWatch = Stopwatch.StartNew();
        jumpParam.DiagonalMovement = (DiagonalMovement)cbbJumpType.SelectedIndex;
        jumpParam.CurIterationType = cbUseRecursive.Checked ? IterationType.RECURSIVE : IterationType.LOOP;
        jumpParam.Reset(startPos, endPos);
        var path = JumpPointFinder.FindPath(jumpParam);
        elapsedJumpPoint += stopWatch.ElapsedMilliseconds;
    }

    {
        searchGrid.Reset();

        var stopWatch = Stopwatch.StartNew();
        starParam.DiagonalMovement = (DiagonalMovement)cbbJumpType.SelectedIndex;
        starParam.SetHeuristic(HeuristicMode.EUCLIDEAN);
        starParam.Reset(startPos, endPos);
        var path = AStarFinder.FindPath(starParam);
        elapsedAStar += stopWatch.ElapsedMilliseconds;
    }
}

MessageBox.Show(string.Format("JP time : {0}ms\nA* time : {1}ms", elapsedJumpPoint / (float)profileCount, elapsedAStar / (float)profileCount));

RandomizeGrid 代码在这里:

void RandomizeGrid(BaseGrid searchGrid, float randomPercent = 0.2f)
{
    if (searchGrid != null)
    {
        var width = searchGrid.width;
        var height = searchGrid.height;

        for (int i = 0; i < width; ++i)
        {
            for (int j = 0; j < height; ++j)
            {
                searchGrid.SetWalkableAt(new GridPos(i, j), true);
            }
        }

        var random = new Random();
        for (int i = 0; i < width * height * randomPercent; ++i)
        {
            var randWidth = random.Next(0, width);
            var randHeight = random.Next(0, height);
            searchGrid.SetWalkableAt(new GridPos(randWidth, randHeight), false);
        }
    }
}

一些测试结果也列在下面:

|随机百分比 |太平绅士 | A* |

| 0.05 | ~8.7 毫秒 | ~8.2 毫秒 |

| 0.1 | ~11 毫秒 | ~14.3 毫秒 |

| 0.2 | ~15 毫秒 | ~13.7 毫秒 |

| 0.5 | ~20.5 毫秒 | ~22 毫秒 |

跳转点搜索显着减少了 A* 优先级队列的大小,但查找每个跳转点本身所花费的时间要长得多。但是,它节省了大量时间,因为它不需要存储和维护可以从 A* 生成的大型优先级队列,而在 A* 中保持排序的推送操作可能很昂贵。较小的队列也有助于缓存行。但是跳跃点搜索最终可以扩展比 A* 更多的节点,即使它们没有被添加到开放列表/优先级队列中。

要回答关于 运行 时间是否严格更好的问题,这实际上取决于算法的实现以及给定的地图。由于打开列表的大小要小得多,因此内存使用通常会更好。如果网格像迷宫或有很多障碍物,速度通常会降低,因为它最终会增加很多跳跃点,这可能很昂贵。

我针对 A* (https://github.com/YashTrikannad/mpl/blob/master/include/mpl/jps.h) 对跳跃点搜索的实现进行了基准测试,跳跃点搜索在 1000x1000 二维网格上平均快了 10 倍 运行1000 运行s 有 4-5 个大型障碍物(不是迷宫)。