Possible Duplicate:
Erasing from a std::vector while doing a for each?
I'm trying to implement vertice coloring according to this algorithm;
/*
Given G=(V,E):
Compute Degree(v) for all v in V.
Set uncolored = V sorted in decreasing order of Degree(v).
set currentColor = 0.
while there are uncolored nodes:
set A=first element of uncolored
remove A from uncolored
set Color(A) = currentColor
set coloredWithCurrent = {A}
for each v in uncolored:
if v is not adjacent to anything in coloredWithCurrent:
set Color(v)=currentColor.
add v to currentColor.
remove v from uncolored.
end if
end for
currentColor = currentColor + 1.
end while
*/
I don't understand "add v to currentColor." line but I supposed, it means assing currentColor to v. Therefore what is the "set"? Anyway the problem is erasing element in vector while iterating it. This is the code.
vector<struct Uncolored> uc;
vector<struct Colored> c;
int currentColor = 0;
struct Colored A;
struct Colored B;
vector<struct Uncolored>::iterator it;
vector<struct Uncolored>::iterator it2;
vector<struct Colored>::iterator it3;
for(it=uc.begin();it<uc.end();it++){
A.id = (*it).id;
uc.erase(uc.begin());
A.color = currentColor;
c.push_back(A);
for(it2=uc.begin();it2<uc.end();it2++) {
it3=c.begin();
while(it3 != c.end()) {
if( adjacencyMatris[(*it2).id][(*it3).id] == 0 ) {
B.id = (*it2).id;
it2 = uc.erase(it2);
B.color = currentColor;
c.push_back(B);
}
it3++;
}
}
currentColor = currentColor + 1;
}
I think it2 = uc.erase(it2);
line is already general use but It gives run time error.
In the line:
it2 = uc.erase(it2);
an element pointed by iterator it2
is removed from the vector, elements are shifted in memory in order to fill that gap which invalidates it2
. it2
gets a new value and now points to the first element after the the removed one or the end of the vector (if removed element was the last one). This means that after erasing an element you should not advance it2
. An alternative to proposed remove-erase idiom
is a simple trick:
for(it2 = uc.begin(); it2 != uc.end();)
{
...
if(...)
{
it2 = uc.erase(it2);
}
else
{
++it2;
}
...
}
You can read more about this here.
Edit: Regarding your comment, you can use a flag to pass the information whether an element has been erased or not, and you can check it when you get out from the inner loop:
for(it2=uc.begin(); it2 != uc.end();)
{
bool bErased = false;
for(it3 = c.begin(); it3 != c.end(); ++it3)
{
if(adjacencyMatris[(*it2).id][(*it3).id] == 0 )
{
B.id = (*it2).id;
it2 = uc.erase(it2);
bErased = true;
B.color = currentColor;
c.push_back(B);
break;
}
}
if(!bErased)
++it2;
}
After you've erased an element from uc
you need to break from the inner loop. In the next iteration of the outer loop you'll be able to access the next element in the uc
through a valid iterator.
Instead of working with iterator
types, store an index into the vector
. When you need an iterator--perhaps for passing into erase
--you can say begin() + myIndex
to generate an iterator.
This also makes the loop look more familiar, e.g.
for(ind=0; ind < uc.size(); ind++) {
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With