简体   繁体   中英

std::map overwriting wrong keys

So I was writing a code for solving the maze using BFS algorithm. Since I have to show the path, I am using a map for storing the parent node. Unfortunately, the parent node gets overwritten when it should've been left untouched. Here's the code

//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;
}

When I run this BFS algorithm with a maze I built, the map shows some very weird behavior. Here's an example:

原本的 This is the original map. Clearly from the code and the debugger, there should be one more entry for adjCell (2,1) with parent as (1,1) right? But no:

不变的 Nothing happens. This gets completely ignored. Ok let's say system is trolling me this once :(. At least now there should be new entry for (1,3) with (1,2) as parent. But no:

覆写 The value get's overwritten! How's this possible? Shouldn't there be new value? How come (1,2) & (1,3) are same?

Finally here's a weird observation: If I change this code in Point class

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

to

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

The size of parent at the end changes from 7 to 13. My best guess is that there is something wrong with the insertion in map class. Since the operator < is 'key' for it, I could be missing something. But I don't have any definitive leads. Would really appreciate any help.

The operator< function implementation is incorrect. It does not meet the criteria for strictly weak ordering of keys.

Use

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

If you want to hand code the correct implementation, use:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM