2d Vector Insertions in C++ - c++

Currently working on a graph representation using a vector of vectors. I am attempting to insert a vector of edges at a specific location within adjacencies. adjacencies is defined as adjacencies = new std::vector< std::vector<Edge*>* >;
I am running into an issue with the vector not inserting at the specific .stateId location. It is quite possible the logic isn't what I intend it to be. Do i need to be resizing the vector? From documentation, I would assume the vector will resize automatically when inserting at a location not currently in the vector. I appreciate the clarification.
Here is my method:
/*
* Connecting Edge vertF -----> vertT via weigh
* adjacencies[v][e]
*/
void GraphTable::InsertEdgeByWeight(Vertex* vertF,Vertex* vertT, char weigh){
Edge* tempEdge = new Edge(vertT,weigh);
/*
* Need to figure out how to properly allocate the space in adjacencies.size()
* Test 4 works with initial ID 0 but not test 5 with ID 4
*/
std::vector<Edge*>* temp_vec = new vector<Edge*>;
temp_vec->push_back(tempEdge);
/*if vector at location doesnt exist, we will push a new vector of edges otherwise we
* will need to push the edge into the current vector
*/
if(adjacencies->size()<vertF->thisState.stateId){
adjacencies->resize(vertF->thisState.stateId);
adjacencies[vertF->thisState.stateId].push_back(temp_vec);
}else{
adjacencies[vertF->thisState.stateId].push_back(temp_vec);
}
cout<< adjacencies->capacity() << endl;
//cout<< adjacencies->max_size() << endl;
}

You are resizing adjacencies to a value of vertF->thisState.stateId and then calling adjacencies[vertF->thisState.stateId].
If the size of a vector/array is "x", then the highest index is "x-1".
So you should write this instead -:
adjacencies[vertF->thisState.stateId-1].push_back(temp_vec);
Edit : As Ankit Garg pointed out in the comments, you should probably push tempEdge directly to adjacencies instead of creating a temporary vector.

Expanding from my comment, I think you must do something like this:
if(adjacencies->size() < vertF->thisState.stateId)
{
// the vector does not exist, hence push_back the new vector
.....
}
else
{
// vector already exists, so just push_back the edge
adjacencies[vertF->thisState.stateId].push_back(temp_edge);
}

Related

What is the best way to get a permutation index list of a given vector

In my application I solve a geometric problem on a given list of points.
0 x0 y0
1 x1 y1
...
The solution file should contain a specific ordering of the points which are represented as a list of their indexes.
1
0
...
After solving the problem I have a result = std::vector<Point>() vector of point objects in a certain order as well as the original list of points as an original = std::vector<Point>() vector. Both vectors naturally have the same size. To generate the output file I go through the result vector and search for the index of the point in the original vector. This is quite inefficient because it does need O(n^2) time. As a slight improvement I do the following:
std::ofstream out(filename);
std::vector<int> indices(instance.size);
std::iota(indices.begin(), indices.end(), 0);
for(auto &point : instance.result.points)
{
for(std::size_t i=0; i<indices.size(); i++)
{
int id = indices[i];
if(point == instance.points[id])
{
out << id << std::endl;
indices.erase(indices.begin()+i);
break;
}
}
}
out.close();
This allows me to not revisit the points that I already found before. Sadly for a 1 million point instance, this process exceeds my time limit and I don't want the export of my solution to take more time than solving the problem itself. Is there a way to efficiently get the indexes of a premutation of some vector in C++? The solution can use a lot of memory if desired.
One of the simple to implement and quite efficient solution is to create a temporary std::unordered_map<Point,size_t> where key is the point and value is position inside original, then do lookup in that map. Details on how to use your (or library provided) data type as a key in std::unordered_map provided here
You can extend the Point structure to contain the original id, besides the position.

Segmentation fault during erasing from vector

I'm developing an Asteroid game clone but I'm facing a problem during erasing elements from vector of asteroids. So generally when I hit the asteroid it should split into 3 parts. So I create 3 new asteroids and erase the old one an then it crashes.
void Level::missleAsteroidCollision(){
std::cout<<this->asteroidVector.size()<<std::endl;
for(auto ptr = this->missleVector.begin();ptr!=this->missleVector.end();++ptr){
sf::FloatRect missleBounds = (*ptr)->shape.getGlobalBounds();
for(auto ptrTwo = this->asteroidVector.begin(); ptrTwo!= this->asteroidVector.end();++ptrTwo){
if(missleBounds.intersects((*ptrTwo)->shape.getBounds()) && (*ptrTwo)->isFinalForm == false){
for(int i = 0; i < 3; ++i){
this->createAsteroid((*ptrTwo)->origin,true);
}
delete *ptrTwo;
this->asteroidVector.erase(ptrTwo);
}
else if(missleBounds.intersects((*ptrTwo)->shape.getBounds()) && (*ptrTwo)->isFinalForm == true){
delete *ptrTwo;
this->asteroidVector.erase(ptrTwo);
}
}
}
}
First of all, when you use the .erease function, the iterator is changed so you need to update it, in your case, ptr = this->asteroidVector.erase(ptrTwo); the iterator will now point to the next element after deletion so keep that in mind (either you decrease the pointer by one or you only increase the ptr (ptr++) if you did not use the .erase function.
Secondly, I believe this->createAsteroid((*ptrTwo)->origin,true); creates new items, this will also invalidate the iterator, so one fix could be, creating the new asteroids after checking and deleting the old one. Maybe store the new asteroids in a vector created before the for loop, adding the new meteorites there and after the for loop add the vector to your current vector of asteroids.
Inserting an item into a vector (whether or not at the end of the vector) can invalidate all iterators to that vector. I suspect your createAsteroid does so.

How to iterate through a list while adding items to it

I have a list of line segments (a std::vector<std::pair<int, int> > that I'd like to iterate through and subdivide. The algorithm would be, in psuedocode:
for segment in vectorOfSegments:
firstPoint = segment.first;
secondPoint = segment.second;
newMidPoint = (firstPoint + secondPoint) / 2.0
vectorOfSegments.remove(segment);
vectorOfSegments.push_back(std::make_pair(firstPoint, newMidPoint));
vectorOfSegments.push_back(std::make_pair(newMidPoint, secondPoint));
The issue that I'm running into is how I can push_back new elements (and remove the old elements) without iterating over this list forever.
It seems like the best approach may be to make a copy of this vector first, and use the copy as a reference, clear() the original vector, and then push_back the new elements to the recently emptied vector.
Is there a better approach to this?
It seems like the best approach may be to make a copy of this vector first, and use the copy as a reference, clear() the original vector, and then push_back the new elements to the recently emptied vector.
Almost. You don't need to copy-and-clear; move instead!
// Move data from `vectorOfSegments` into new vector `original`.
// This is an O(1) operation that more than likely just swaps
// two pointers.
std::vector<std::pair<int, int>> original{std::move(vectorOfSegments)};
// Original vector is now in "a valid but unspecified state".
// Let's run `clear()` to get it into a specified state, BUT
// all its elements have already been moved! So this should be
// extremely cheap if not a no-op.
vectorOfSegments.clear();
// We expect twice as many elements to be added to `vectorOfSegments`
// as it had before. Let's reserve some space for them to get
// optimal behaviour.
vectorOfSegments.reserve(original.size() * 2);
// Now iterate over `original`, adding to `vectorOfSegments`...
Don't remove elements while you insert new segments. Then, when finished with inserting you could remove the originals:
int len=vectorOfSegments.size();
for (int i=0; i<len;i++)
{
std::pair<int,int>& segment = vectorOfSegments[i];
int firstPoint = segment.first;
int secondPoint = segment.second;
int newMidPoint = (firstPoint + secondPoint) / 2;
vectorOfSegments.push_back(std::make_pair(firstPoint, newMidPoint));
vectorOfSegments.push_back(std::make_pair(newMidPoint, secondPoint));
}
vectorOfSegments.erase(vectorOfSegments.begin(),vectorOfSegments.begin()+len);
Or, if you want to replace one segment by two new segments in one pass, you could use iterators like here:
for (auto it=vectorOfSegments.begin(); it != vectorOfSegments.end(); ++it)
{
std::pair<int,int>& segment = *it;
int firstPoint = segment.first;
int secondPoint = segment.second;
int newMidPoint = (firstPoint + secondPoint) / 2;
it = vectorOfSegments.erase(it);
it = vectorOfSegments.insert(it, std::make_pair(firstPoint, newMidPoint));
it = vectorOfSegments.insert(it+1, std::make_pair(newMidPoint, secondPoint));
}
As Lightning Racis in Orbit pointed out, you should do a reserve before either of these approaches. In the first case do reserve(vectorOfSegmets.size()*3), in the latter reserve(vectorOfSegmets.size()*2+1)
This is easiest solved by using an explicit index variable like this:
for(size_t i = 0; i < segments.size(); i++) {
... //other code
if(/*condition when to split segments*/) {
Point midpoint = ...;
segments[i] = Segment(..., midpoint); //replace the segment by the first subsegment
segments.emplace_back(Segment(midpoint, ...)); //add the second subsegment to the end of the vector
i--; //reconsider the first subsegment
}
}
Notes:
segments.size() is called in each iteration of the loop, so we really reconsider all appended segments.
The explicit index means that the std::vector<> is free to reallocate in the emplace_back() call, there are no iterators/pointers/references that can become invalid.
I assumed that you don't care about the order of your vector because you add the new segments to the end of the vector. If you do care, you might want to use a linked list to avoid quadratic complexity of your algorithm as insertion/deletion to/from an std::vector<> has linear complexity. In my code I avoid insertion/deletion by replacing the old segment.
Another approach to retain order would be to ignore order at first and then reestablish order via sorting. Assuming a good sorting algorithm, that is O(n*log(n)) which is still better than the naive O(n^2) but worse than the O(n) of the linked list approach.
If you don't want to reconsider the new segments, just use a constant size and omit the counter decrement:
size_t count = segments.size();
for(size_t i = 0; i < count; i++) {
... //other code
if(/*condition when to split segments*/) {
Point midpoint = ...;
segments[i] = Segment(..., midpoint); //replace the segment by the first subsegment
segments.emplace_back(Segment(midpoint, ...)); //add the second subsegment to the end of the vector
}
}

segmentation fault in iterator

I have created a multimap for my road points. The key refers to the road number and the values are vec3 points that make up the road.
I am trying to iterate through the values of each key point and create a road segment at each point on the road (except the last), adjust the values to be on the road points and then store them in a std::vector.
The RoadSegment constructor creates 6 vec3 points and pushes them onto a std::vector.
I have a segmentation fault in the line marked in bold
[for(mapIt = it.first; mapIt != it.second; ++mapIt)]
When i take out the lines creating the new objects and pushing them onto the std::vector it works fine.
Can anyone tell me what the problem is / a solution to the problem??
Many thanks in advance
std::vector<glm::vec3>::iterator SegIt;
for(int i = 0; i < m_genRoads->getKeyValueData().size(); i++)
{
int numberDesired = m_genRoads->getMultimapData().count(i) - 1;
std::multimap<int, glm::vec3>::iterator mapIt;
std::pair<std::multimap<int, glm::vec3>::iterator, std::multimap<int, glm::vec3>::iterator> it;
it = m_genRoads->getMultimapData().equal_range(i);
for(mapIt = it.first; mapIt != it.second; ++mapIt)
{
int distance = std::distance(it.first, mapIt);
if(distance != numberDesired)
{
RoadSegement* roadSegmentPointer = new RoadSegement();
// FUNCTIONS TO ADJUST COORD VALUES TO MATCH THE ROAD POINTS
m_segmentArray.push_back(roadSegmentPointer);
}
else
{
continue;
}
///SOME BUFFER BINDING STUFF
The issue seems to be that you're using iterators that do not exist, all due to returning a temporary object.
it = m_genRoads->getMultimapData().equal_range(i);
Since getMultiMapData() returns a copy of the multimap, that multimap is gone after the line is executed, thus rendering any iterators invalid.
One solution is to return a reference to the multimap, not a new copy of the multimap.
std::multimap<int, glm::vec3>& GenerateRoads::getMultimapData() { return m_roadsMultimap; }

BFS using adjacency lists in STL

I am trying to write a program for implementing BFS in C++ using STL. I am representing the adjacency list using nested vector where each cell in vector contains a list of nodes connected to a particular vertex.
while(myQ.size()!=0)
{
int j=myQ.front();
myQ.pop();
int len=((sizeof(adjList[j]))/(sizeof(*adjList[j])));
for (int i=0;i<len;i++)
{
if (arr[adjList[j][i]]==0)
{
myQ.push(adjList[j][i]);
arr[adjList[j][i]]=1;
dist(v)=dist(w)+1;
}
}
}
myQ is the queue i am using to keep the nodes along whose edges i will be exploring the graph. In the notation adjList[j] represents the vector pointing to the list and adjList[j][i] represents a particular node in that list. I am storing whether i have explored a particular node by inputting 1 in the array arr. Also dist(v)=dist(w)+1 is not a part of the code but i want to know how i can write it in the correct syntax where my v is the new vertex and w is the old one which discovers v i.e w=myQ.front().
If I have understood your problem, then you want a data structure to store the distances of the graph nodes.
This can be easily done using map.
Use this:
typedef std::map <GraphNode*, int> NodeDist;
NodeDist node_dist;
Replace dist(v)=dist(w)+1; with:
NodeDist::iterator fi = node_dist.find (w);
if (fi == node_dist.end())
{
// Assuming 0 distance of node w.
node_dist[v] = 1;
}
else
{
int w_dist = (*fi).second;
node_dist[v] = w_dist + 1;
}
Please let me if I have misunderstood your problem or the given solution does not work for you. We can work on that.