Элемент стирания в векторе при повторении одного и того же вектора
Возможный дубликат:
Удаление из std::vector при выполнении для каждого?
Я пытаюсь реализовать окраску по вертикали в соответствии с этим алгоритмом;
/*
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
*/
Я не понимаю, добавьте v в currentColor. "но я предположил, что это означает, что currentColor соответствует v. Поэтому что такое" set"? В любом случае проблема заключается в стирании элемента в векторе при его повторении. Это код.
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;
}
Я думаю, что строка it2 = uc.erase(it2);
уже используется, но дает ошибку времени выполнения.
Ответы
Ответ 1
В строке:
it2 = uc.erase(it2);
элемент, указанный итератором it2
, удаляется из вектора, элементы смещаются в памяти, чтобы заполнить этот пробел, который делает недействительными it2
. it2
получает новое значение и теперь указывает на первый элемент после удаленной или конец вектора (если удаленный элемент был последним). Это означает, что после стирания элемента вы не должны продвигаться it2
. Альтернативой предложенному remove-erase idiom
является простой трюк:
for(it2 = uc.begin(); it2 != uc.end();)
{
...
if(...)
{
it2 = uc.erase(it2);
}
else
{
++it2;
}
...
}
Вы можете прочитать об этом здесь.
Edit:
Что касается вашего комментария, вы можете использовать флаг для передачи информации о стирании элемента или нет, и вы можете проверить его, когда вы выходите из внутреннего цикла:
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;
}
После удаления элемента из uc
вам нужно выйти из внутреннего цикла. В следующей итерации внешнего цикла вы сможете получить доступ к следующему элементу в uc
через действительный итератор.
Ответ 2
Вместо работы с типами iterator
сохраните индекс в vector
. Когда вам нужен итератор - возможно, для перехода в erase
- вы можете сказать begin() + myIndex
, чтобы сгенерировать итератор.
Это также делает цикл более знакомым, например
for(ind=0; ind < uc.size(); ind++) {
Ответ 3
vector::erase()
может аннулировать итераторы, указывая на вектор.
Это делает недействительным весь итератор и ссылки на позицию (или первое) и его последующие элементы.
Вам нужно добавить результат erase
к итератору (он будет указывать на элемент сразу после его удаления) и использовать его поэтому. Заметим, что в
for(it=uc.begin();it<uc.end();++it){
A.id = (*it).id;
uc.erase(uc.begin());
...
}
Итератор it
недействителен после uc.erase
, поэтому последующий ++ и использование могут привести к ошибке выполнения.
Аналогично, хотя вы назначаете результат стирания на it2
, вызов может аннулировать it
, который не изменяется.
Лучше всего либо перезапустить свой алгоритм с самого начала после каждого erase()
, либо если вы можете его изменить, чтобы он мог продолжить работу с итератора, возвращаемого erase
, сделайте это, чтобы получить некоторую эффективность.
Ответ 4
У вас есть ошибка времени выполнения, потому что it2 = uc.erase(it2);
возвращает итератор после последнего удаленного элемента, поэтому it2++
in for(it2=uc.begin();it2<uc.end();it2++)
выходит за пределы последнего элемента.
Попробуйте изменить его, если:
if( adjacencyMatris[(*it2).id][(*it3).id] == 0 ) {
B.id = (*it2).id;
uc.erase(it2);
B.color = currentColor;
c.push_back(B);
break;
}