Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: [C++] STL, vector  (Прочитано 19507 раз)
0 Пользователей и 5 Гостей смотрят эту тему.
The Nameless One
Помогающий

ru
Offline Offline
Пол: Мужской

« : 08-09-2009 07:06 » 

Привет)
Удаление элемента из середины вектора - это правильно, можно так делать?

К примеру, в цикле просматриваются все элементы вектора, при выполнении определенного условия, текущий элементы удаляется:
Код:
vector <just> v;
vector <just>::iterator it=v.begin();
while(it!=v.end())
{
   it->foo();
   if(it->a) it=v.erase(it);
   else it++;
}
Добавление элементов происходит вне цикла.

Так нормально поступать? Или будет постоянное перераспределение памяти?
Нужно достичь как можно меньшей нагрузки на процессор.

Заранее благодарен за ответы.
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #1 : 08-09-2009 07:44 » 

перераспределения не будет, но вот копирование больших кусков данных будет
т.е. когда ты удаляешь элемент все элементы после него будут смещены на 1 элемент влево.

кроме того, erase вызывает инвалидацию итераторов, как следствие цикл надо запускать сначала
посмотри в сторону алгоритма remove_if
не забываем, что remove_if не удаляет хвост контейнера поэтому
делаем такд
Код:
bool check_just(just & j)
{
  j.foo();
  return j.a;
}

v.erase(std::remove_if(v.begin(), v.end(), check_just), v.end());

Записан

Странно всё это....
The Nameless One
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 08-09-2009 07:55 » new

Спасибо, посмотрю.

Насчёт инвалидации итераторов после erase, а разве erase() не возвращает итератор, следующий за удалённым? Именно потому делал it=v.erase(it), а не просто v.erase(it) ?
Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 08-09-2009 07:58 » 

Насчёт инвалидации итераторов после erase, а разве erase() не возвращает итератор, следующий за удалённым?
И это будет единственный валидный итератор, указывающий на элементы, следующие за удалённым. То есть, в общем случае уже нельзя полагаться на любые другие ранее полученные итераторы для данного вектора, поскольку сдвиг данных приводит к тому, что они могут указывать совсем не туда, куда должны бы.

Что касается цикла - не совсем согласен с LogRus: поскольку полученный итератор будет корректным, можно продолжать удаление с него. Только потери производительности будут существенными, поскольку каждое удаление одного элемента будет приводить к перемещению в среднем size/2 элементов ближе к началу буфера. То есть, сложность получается в худшем случае квадратичная.
« Последнее редактирование: 08-09-2009 08:02 от Вад » Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 08-09-2009 08:09 » 

Кстати, remove_if поступает более хитро и за счёт этого экономит время: он не удаляет элементы по одному, а просто копирует вектор сам в себя, пропуская элементы, которые должны быть удалены. В результате, сложность алгоритма линейная по копированию, а в конце вектора оказываются не удалённые элементы, а те, которые там были до копирования в себя.
« Последнее редактирование: 08-09-2009 08:12 от Вад » Записан
The Nameless One
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 08-09-2009 08:16 » 

А если перед удалением менять местами последний и удаляемый, а после этого удалять?

Если текущий элемент не последний, то
temp=v.back();
v.back()=it;
it=temp;
v.erase(v.back());

Как-то так можно делать? Насчёт back() не уверенн, вроде она возращает ссылку на последний элемент.


P.S. Думаю, можно адреса менять местами, а не сами объекты -  *v.back()=*it;
« Последнее редактирование: 08-09-2009 08:26 от The Nameless One » Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 08-09-2009 09:13 » 

А зачем так усложнять, если erase-remove_if хорошо справляется с задачей?

Тем более, что v.back() = *it - лишнее, ведь ты следующим действием удаляешь его. И ещё: back возвращает не итератор, а прямую ссылку, поэтому присваивать её итератору не получится.

Если же очень не хочется писать предикат для remove_if, то, по крайней мере, можно же взять и посмотреть, как сама remove_if работает Ага
The behavior of this function template is equivalent to:
Код:
template < class ForwardIterator, class Predicate >
  ForwardIterator remove_if ( ForwardIterator first, ForwardIterator last,
                              Predicate pred )
{
  ForwardIterator result = first;
  for ( ; first != last; ++first)
    if (!pred(*first)) *result++ = *first;
  return result;
}
Записан
The Nameless One
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 08-09-2009 11:00 » 

Думаю, что копирование целого вектора (кроме удаляемого) каждый раз при удалении - больно долго для моего случая.

Я решил, что будет быстрее ставить удаляемый элемент в конец вектора и только после этого его удалять, чтобы не было сдвигов влево и чтобы не было лишних копирований - поменять местами два элемента всегда быстрее, чем копировать вектор при удалении элемента методом remove_if - разве я не прав?
Вся для скорости.
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #8 : 08-09-2009 11:05 » 

Если тебе так важна скорость - сделай свой список, хранящий указатели на объекты и нужными ф-ми. Быстрей не бывает. А работы на полчаса.

В крайнем случае храни в векторе не сами объекты, а указатели на них. В этом случае объём премещаемых, копируемых и тд данных сократится до максимум N*размер указателя, где N - число элементов в векторе.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #9 : 08-09-2009 11:07 » 

The Nameless One,  так всё равно же придётся по кольцу элементы двигать Улыбаюсь
Записан

Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #10 : 08-09-2009 11:08 » 

зы Да даже просто добавь к своему типу just два поля:

just *m_pPrev;
just *m_pNext;

И уже можно делать список.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 08-09-2009 11:25 » 

Алексей1153++, не придётся. Если не задаваться целью сохранять в векторе порядок при удалении.
The Nameless One, если очень хочется, и порядок в векторе не заботит - то да, так будет быстрее всего: поменять удаляемый элемент местами с последним и затем удалить последний элемент.

Только нельзя делать vec.erase(vec.back()), придётся делать resize или явно получать итератор на последний элемент (vec.end() -1)
Записан
The Nameless One
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 08-09-2009 11:48 » 

Всем большое спасибо!
Да, порядок векторе не важен. В том числе поэтому и не хотелось связываться с предикатами.
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #13 : 09-09-2009 02:44 » 

The Nameless One, а зачем вектор кстати?
почему не дек или лист?
Записан

Странно всё это....
The Nameless One
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 09-09-2009 09:49 » 

До list я ещё не дошёл просто Улыбаюсь
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #15 : 09-09-2009 10:11 » 

The Nameless One, тебе бы лучше со своих списков начать. С теории. Полезней будет и для понимания STL.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
The Nameless One
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #16 : 09-09-2009 21:20 » 

Джон, спасибо, так и сделаю))
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #17 : 10-09-2009 06:14 » 

Кстати, посмотри на форуме. Мы уже как-то раз кому-то помогали на тему списков, очередей и стеков.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines