【问题标题】:std::map overwriting wrong keysstd::map 覆盖错误的键
【发布时间】:2018-04-10 03:32:27
【问题描述】:

所以我正在编写一个使用 BFS 算法解决迷宫的代码。由于我必须显示路径,因此我使用地图来存储父节点。不幸的是,当父节点本应保持不变时,它被覆盖了。这是代码

//Data structure to store the coordinates for easy access
class Point
{
public:
    int x;
    int y;
    // For using map
    bool operator<(const Point& p) const {
        return this->x < p.x && this->y < p.y;
    }
    bool operator==(const Point& p)const {
        return this->x == p.x && this->y == p.y;
    }
};


// A function to be used in algo
// Return: Bool whether the value is in range
bool isValid(int row, int col)
{
    return (row >= 0) && (row < ROW) &&
        (col >= 0) && (col < COL);
}

// Off sets for the neighbours
int rowOffsets[] = { -1, 0, 0, 1 };
int colOffsets[] = { 0, -1, 1, 0 };


// The main BFS Algorithm
vector<Point> BFS(int mat[ROW][COL], Point source, Point destination)
{

    bool visited[ROW][COL]; // An array to check whether the node is visited
    memset(visited, false, sizeof(visited)); // Set all the values to false

                                             // Mark the source as visited
    visited[source.x][source.y] = true;

    // Change the ! and * to movable spaces
    for (int i = 0; i < ROW; ++i)
        for (int j = 0; j < COL; ++j)
            if (mat[i][j] == 99 || mat[i][j] == -01)
                mat[i][j] = 0;

    // Create the queue
    queue<Point> q;

    // The parent map. Second denotes the parent for the first.
    map<Point, Point> parent;

    q.push(source);  // Enqueue source cell

    // Let's Start!
    bool success = false;
    while (!q.empty())
    {
        Point current = q.front();


        // Reached the destination?
        if (current.x == destination.x && current.y == destination.y) {
            success = true;
            break; // Continue to the next stuff
        }
        // Deque it
        q.pop();
        // Continue BFS with other nodes
        for (int i = 0; i < 4; i++)
        {
            int row = current.x + rowOffsets[i];
            int col = current.y + colOffsets[i];

            // if adjacent cell is valid, has path and not visited yet, enqueue it.
            if (isValid(row, col) && !mat[row][col] && !visited[row][col])
            {
                // mark cell as visited and enqueue it
                visited[row][col] = true;
                Point Adjcell = { row, col };
                parent[Adjcell] = current; // Certify the parent
                q.push(Adjcell);
            }
        }
    }

    // Trace back
    if (!success)
        return {};
    Point node = parent[destination]; // The first path

    vector<Point> path;
    while (node.x != source.x || node.y != source.y) {
        path.push_back(node);
        node = parent[node];
    }
    return path;
}

当我用我构建的迷宫运行这个 BFS 算法时,地图显示了一些非常奇怪的行为。这是一个例子:

这是原始地图。从代码和调试器中可以清楚地看出,adjCell (2,1) 应该还有一个条目,其父项为 (1,1) 对吧?但是没有:

什么都没发生。这被完全忽略了。好吧,假设系统曾经拖钓过我一次 :(。至少现在应该有 (1,3) 的新条目,以 (1,2) 作为父项。但是没有:

值被覆盖!这怎么可能?不应该有新的价值吗?为什么 (1,2) 和 (1,3) 是一样的?

最后有一个奇怪的发现:如果我在 Point 类中更改此代码

bool operator<(const Point& p) const {
    return this->x < p.x && this->y < p.y;
}

bool operator<(const Point& p) const {
    return this->x < p.x;
}

最后 parent 的大小从 7 变为 13。我最好的猜测是 map 类中的插入有问题。由于运算符

【问题讨论】:

  • 编辑您的问题以包含minimal reproducible example
  • 好吧,对于您的第二个比较函数,具有相同 x 值的任何两个点都被认为是完全等价的。想想这个。
  • IIRC,std::map 的比较器依赖于它表现出你的不提供的 严格的弱排序,在你的 (1, 2) &lt; (2, 1)(2, 1) &lt; (1, 2) 中都是 @987654336 @ 这意味着地图可以认为它们相等
  • 对于一个合适的比较函数,你想比较X值,如果不相等,返回比较结果。如果它们相等,则比较 Y 值并返回结果。将其实现为非成员函数以允许双方进行隐式转换也是一个好主意。
  • return this-&gt;x &lt; p.x &amp;&amp; this-&gt;y &lt; p.y; -- 考虑使用std::tiereturn std::tie(x, y) &lt; std::tie(p.x, p.y);

标签: c++ algorithm dictionary breadth-first-search


【解决方案1】:

operator&lt; 函数实现不正确。它不符合严格弱排序键的标准。

使用

bool operator<(const Point& p) const {
    return std::tie(this->x, this->y) < std::tie(p.x, p.y);
}

如果您想手动编写正确的实现代码,请使用:

bool operator<(const Point& p) const {
    if ( this->x != p.x )
    {
       return (this->x < p.x);
    }
    return (this->y < p.y);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    • 1970-01-01
    • 2022-06-14
    • 1970-01-01
    • 2019-09-18
    • 2018-08-01
    • 1970-01-01
    相关资源
    最近更新 更多