Search code examples
c++algorithma-star

How to add elemnts in Linked vector of structure elements


I have a structure called grid:

struct grid {
    grid *parent;
    int x, y;
    float f, g, h;
    };

I also create a vector of struct grid: vector<grid> open Below is part of code for path-finding. I am trying to create a new grid called neighbor and in each iteration i add it to the open vector but since neighbor is changed every iteration, it is not getting added properly to the open vector. What is a more efficient way to do this? How to add to the open vector? Basically how to implement a linked vector of structure members instead of linked list?

while( !open.empty() )
    {
        grid current, neighbor;
        current=//... minimum-value node in the open vector
        for(vector<grid>::iterator it = open.begin(); it != open.end();++it )
            if((it->x == current.x) &&(it->y == current.y))
               it=open.erase(it);

        for(i=0;i<4;i++)
        {
            neighbor.x=current.x+neighbor_primitves[i][0];
            neighbor.y=current.y+neighbor_primitves[i][1];
            if( (neighbor.x>=0) && (neighbor.x<=100) && (neighbor.y>=0) && (neighbor.y<=100))
            {
                neighbor.parent=new grid;
                neighbor.parent->x=current.x;
                neighbor.parent->y=current.y;
                neighbor.g=current.g+1;
                neighbor.h=heuristic(neighbor,goal);
                neighbor.f=neighbor.g+neighbor.h;
                if(isitinNless(neighbor,open))
                   for(vector<grid>::iterator it = open.begin(); it != open.end(); ++it)
                    {
                          if((it->x == neighbor.x) &&(it->y == neighbor.y))
                          it=open.erase(it);
                     }            
                if(!(isitin(neighbor,open)) )
                    open.push_back(neighbor);
            }
        }
        closed.push_back(current);
    }

EDIT:

 grid* test=goal.parent;
 cout<<test->x<<" "<<test->y;

When i add the following lines of codes at the end of while loop, I find that the parents were not updated outside the while loop, i.e. inside while loop i update the parents of each grid member but outside the scope of while loop those updates don't take place as if parents could not be assigned to any grid member. Entire code:

// A star
#include<iostream>
#include <vector>
#include <cmath>

using namespace std;

struct grid {
    grid *parent;
    int x, y;
    float f, g, h;
    };

float heuristic(grid one, grid two)
{
    float norm= (one.x-two.x)*(one.x-two.x)+(one.y-two.y)*(one.y-two.y);
    return (sqrt(norm));
}

bool isitin(grid &ref, vector<grid> &whole)
{
    bool key=false;
    if(whole.empty())
        return key;
    std::vector<grid>::iterator it;
    for(it = whole.begin(); it != whole.end(); ++it)
    {
        if((it->x==ref.x) && (it->y==ref.y))
            key=true;
    }
    return key;
}

bool isitinNless(grid &ref, vector<grid> &whole)
{
    bool key=false;
    if(whole.empty())
        return key;
    /*
    node iter;
    while(!whole.empty())
    {
        iter=whole.back();
        if((iter.x==ref.x) && (iter.y==ref.y))
            key=true;
        whole.pop_back();
    }*/
    std::vector<grid>::iterator it;
    for(it = whole.begin(); it != whole.end(); ++it)
        if((it->x==ref.x) && (it->y==ref.y) && (ref.g < it->g))
            key=true;
    return key;
}

grid& findmin(vector<grid> &open)
{
    int mini=2000000;
    grid mininode;
    /*
    while(!open.empty())
    {
        iter=open.back();
        if(iter.f<mini)
        {
            mini=iter.f;
        }
        open.pop_back();
    }
    */
    std::vector<grid>::iterator it;
    for(it = open.begin(); it != open.end(); ++it) {
        if(it->f<mini)
            {
                mini=it->f;
                mininode=*it;
            }
    }
    return mininode;
}
int main() {

/*
    vector<node*> open;
    vector<node*> closed;

    node *start=new node;
    start->x=50;
    start->y=50;
    start->f=0;
    start->g=0;
    start->h=0;// you can take it as zero. works instea of the actual distnace between goal and start.

    node *goal=new node;
    goal->x=53;
    goal->y=50;
    goal->f=-1;
    goal->g=-1;
    goal->h=0;

    // put the starting node on the open list
    open.push_back(start);
    node *current=new node;
    current=open.back();
    cout<<current->x;
*/
    vector<grid> open;
    vector<grid> closed;
    // neighbor generation scheme
    int neighbor_primitves[4][2],i;
    neighbor_primitves[0][0]=1; neighbor_primitves[0][1]=0;
    neighbor_primitves[1][0]=0; neighbor_primitves[1][1]=1;
    neighbor_primitves[2][0]=-1; neighbor_primitves[2][1]=0;
    neighbor_primitves[3][0]=0; neighbor_primitves[3][1]=-1;

    grid start;
    start.parent=NULL;
    start.x=50;
    start.y=50;
    start.f=0;
    start.g=0;
    start.h=0;// you can take it as zero. works instead of the actual distnace between goal and start.

    grid goal;
    goal.parent=&start; // just a cosmetic assignment.
    goal.x=53;
    goal.y=50;
    goal.f=-1;
    goal.g=-1;
    goal.h=0;


    // put the starting node on the open list
    open.push_back(start);

    /*if(isitin(start,open))
        cout<<"YO!!!";
    if(!open.empty())
        cout<<"NO!!!";*/
    /*
    node current;
    current=open.back();
    cout<<current.x;
    */

    while( !open.empty() )//&& !(findmin(open).x==goal.x) && !(findmin(open).y==goal.y) )
    {
        grid current, neighbor;
        // find the node with the least f on the open list, call it "current"
        current=findmin(open);
        cout<<open.size();
        if(current.x==goal.x && current.y==goal.y)
        {
            cout<<"Goal!!!\n";
            break;
        }
        // pop current off the open list
        for(vector<grid>::iterator it = open.begin(); it != open.end(); )
        {
            if((it->x == current.x) &&(it->y == current.y))
                {
                    it=open.erase(it);
                }
            else
                ++it;
        }
        cout<<open.size();
        // generate q's 8 successors and set their parents to current
        for(i=0;i<4;i++)
        {
            neighbor.x=current.x+neighbor_primitves[i][0];
            neighbor.y=current.y+neighbor_primitves[i][1];
            if( (neighbor.x>=0) && (neighbor.x<=100) && (neighbor.y>=0) && (neighbor.y<=100))
            {
                neighbor.parent=new grid;
                neighbor.parent->x=current.x;
                neighbor.parent->y=current.y;
                neighbor.g=current.g+1;
                neighbor.h=heuristic(neighbor,goal);
                neighbor.f=neighbor.g+neighbor.h;
                //if(!(isitinNless(neighbor,open)) && !(isitinNless(neighbor,closed)))
                 //   open.push_back(neighbor);
                if(isitinNless(neighbor,open))
                {
                    // pop neighbor off the open list
                    for(vector<grid>::iterator it = open.begin(); it != open.end(); )
                    {
                        if((it->x == neighbor.x) &&(it->y == neighbor.y))
                            {
                                it=open.erase(it);
                            }
                        else
                            ++it;
                    }
                }
                if(isitinNless(neighbor,closed))
                {
                    // pop neighbor off the closed list
                    for(vector<grid>::iterator it = closed.begin(); it != closed.end(); )
                    {
                        if((it->x == neighbor.x) &&(it->y == neighbor.y))
                            {
                                it=closed.erase(it);
                            }
                        else
                            ++it;
                    }
                }
                if(!(isitin(neighbor,open)) && !(isitin(neighbor,closed)))
                    open.push_back(neighbor);
            }
        }
        closed.push_back(current);
        // cout<<open.size()<<"\n";
        cout<<"\n";
        for(vector<grid>::iterator it = open.begin(); it != open.end(); ++it)
            cout<<it->x<<" "<<it->y<<" "<<it->parent->x<<" "<<it->parent->y<<"\n";
    }
    grid* test=goal.parent;
    cout<<test->x<<" "<<test->y;
    cin.get();
    return 0;
}

Solution

  • Your problem is in findmin. You're expecting that to return a reference to an element of your vector but instead it is returning a reference to an invalid data location:

    grid& findmin(vector<grid> &open)
    {
        int mini=2000000;
        grid mininode; //locally allocated grid
    
        std::vector<grid>::iterator it;
        for(it = open.begin(); it != open.end(); ++it) {
            if(it->f<mini)
                {
                    mini=it->f;
                    mininode=*it; //assigns values in the grid pointed to by it to mininode
                }
        }
        return mininode; //returns a reference to the locally scoped grid
    } //destroys mininode
    

    You can clearly see how this is a problem. A better solution would be replacing findmin with:

    auto& current = *find_min(open.begin(), open.end(), [](const grid& first, const grid& smallest){return first->f < smallest->f;});