STL вопрос новичка
От: ArcD  
Дата: 11.03.04 15:42
Оценка:
Научите пожалуйста как с помощью STL решить следующую задачу:
имею определенный тип данных:
struct PIECE
{
.................
.................
.................
}

PIECE *one_piece;

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

Я пробовал решить эту задачу с помощь динамического массива, но заранее не известно количество элементов. И удаление ненужных элементов из середины массива создает потом проблемы с поиском свободного места, куда можно вставить новый элемент. Да и не думаю, что все это оптимально в плане скорости.

Если можно пожалуйста кусочек кода, поясняющий.
Заране благодарен.
Re: STL вопрос новичка
От: Bell Россия  
Дата: 11.03.04 15:55
Оценка:
Здравствуйте, ArcD, Вы писали:

смотри в сторону std::vector
Любите книгу — источник знаний (с) М.Горький
Re[2]: STL вопрос новичка
От: ArcD  
Дата: 11.03.04 16:04
Оценка:
Здравствуйте, Bell, Вы писали:

B>смотри в сторону std::vector


Спасибо.
Пробовал:

typedef vector<Piece> PEACELIST;
PEACELIST list;

добавляю элементы:

list.push_back(p);

а вот как читать то? Если p=list.pop_back(), то доступ получается последовательный, а нужен произвольный по индексу как в обычном массиве.
Или так нельзя?
Re[3]: STL вопрос новичка
От: Bell Россия  
Дата: 11.03.04 16:12
Оценка:
Здравствуйте, ArcD, Вы писали:

AD>Здравствуйте, Bell, Вы писали:


B>>смотри в сторону std::vector


AD>Спасибо.

AD>Пробовал:

AD>typedef vector<Piece> PEACELIST;

AD>PEACELIST list;

AD>добавляю элементы:


AD>list.push_back(p);


AD>а вот как читать то? Если p=list.pop_back(), то доступ получается последовательный, а нужен произвольный по индексу как в обычном массиве.

AD>Или так нельзя?

Ну, pop_back — это вообще удаление последнего элемента из контейнера.
Надо так:

for(int i = 0; i < list.size(); ++i)
   list[i].field1 = ...


или так:

for(PEACELIST::iterator it = list.begin(), ite = list.end(), it != ite; ++it)
   it->field1 = ...


ЗЫ
list — неудачное название. В STL есть контейнер с этим именем.
Любите книгу — источник знаний (с) М.Горький
Re: STL вопрос новичка
От: Bell Россия  
Дата: 11.03.04 16:17
Оценка:
Здравствуйте, ArcD, Вы писали:

Кстати может будет интересно почитать эту статью
Любите книгу — источник знаний (с) М.Горький
Re: STL вопрос новичка
От: PK Sly http://www.vocord.ru/
Дата: 11.03.04 16:25
Оценка:
AD>количество элементов заранее не известно, надо все это где-то хранить, удалять ненужные, добавлять новые и самое главное обращаться к нужному данному по номеру.

сделай map
VAX/VMS rulez!
Re[4]: STL вопрос новичка
От: Аноним  
Дата: 11.03.04 16:33
Оценка: 1 (1)
Здравствуйте, Bell, Вы писали:

B>ЗЫ

B>list — неудачное название. В STL есть контейнер с этим именем.

Удачное, удачное.
В STL контейнер называется std::list.
Просто не надо всюду using namespace расставлять.
Re[5]: STL вопрос новичка
От: Bell Россия  
Дата: 12.03.04 07:07
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Bell, Вы писали:


B>>ЗЫ

B>>list — неудачное название. В STL есть контейнер с этим именем.

А>Удачное, удачное.

А>В STL контейнер называется std::list.
А>Просто не надо всюду using namespace расставлять.

У меня где-то было написано using namespace std; ?
Любите книгу — источник знаний (с) М.Горький
Re[6]: STL вопрос новичка
От: ArcD  
Дата: 12.03.04 07:29
Оценка:
Здравствуйте, Bell, Вы писали:

Спасибо всем большое. А за статью особенно.
Re[4]: STL вопрос новичка
От: ArcD  
Дата: 12.03.04 09:38
Оценка:
Здравствуйте, Bell, Вы писали:

B>Надо так:


B>
B>for(int i = 0; i < list.size(); ++i)
B>   list[i].field1 = ...
B>


B>или так:


B>
B>for(PEACELIST::iterator it = list.begin(), ite = list.end(), it != ite; ++it)
   it->>field1 = ...
B>


Спасибо большое вот первый способ мне подходит, только вот как удалить элемент из середины векора?

B>
B>PIECE piece;
B>for(int i = 0; i < list.size(); i++)
B>{
B>   piece=list[i];
B>   if (piece.life_time>1000)
B>   {
B>       Здесь надо удалить элемент list[i]. list.erase(...), что ему передать в качестве параметра? i? не подходит, ругается....
B>   }
B>}
B>
Re[5]: STL вопрос новичка
От: Bell Россия  
Дата: 12.03.04 10:04
Оценка:
Здравствуйте, ArcD, Вы писали:

AD>Спасибо большое вот первый способ мне подходит,


Эти методы пракимчески идентичны.

AD>только вот как удалить элемент из середины векора?


B>>
B>>PIECE piece;
B>>for(int i = 0; i < list.size(); i++)
B>>{
B>>   piece=list[i];
B>>   if (piece.life_time>1000)
B>>   {
B>>       Здесь надо удалить элемент list[i]. list.erase(...), что ему передать в качестве параметра? i? не подходит, ругается....
B>>   }
B>>}
B>>


Итак, начнем по порядку.
Удалене из середины вектора одного элемента можно сделать так:
int i = ...//позиция удаления
list.erase(list.begin() + i);


Однако это приводит к тому, что все элементы контейнера, располагавшиеся после удаленного элемента, сдвигаются на одну позицию. Поэтому в цикле применять такой метод нельзя (вернее просто так, без доп. исхищрений, нельзя). Кроме того это крайне неэффективно.
Судя по твоему коду, для твоей задачи идеально подходит стандартный алгоритм remove_if в связке с erase:


#include <vector>
#include <algorithm>

class pred
{
   int n_;
public:
   pred(int n) : n_(n) {}
   bool operator() () { return piece.life_time>n_;}
};

...

std::erase(std::remove_if(list.begin(), list.end(), pred(1000)), list.end());




ЗЫ
Если намерен заняться изучением STL всерьез, то имеет смысл посмотреть в сторону книги C++ Standard Library, The: A Tutorial and Reference
Любите книгу — источник знаний (с) М.Горький
Re[6]: STL вопрос новичка
От: Bell Россия  
Дата: 12.03.04 10:06
Оценка:
Здравствуйте, Bell, Вы писали:


class pred
{
   int n_;
public:
   pred(int n) : n_(n) {}
   bool operator() (const PEECE& piece) { return piece.life_time>n_;}
};
Любите книгу — источник знаний (с) М.Горький
Re[6]: STL вопрос новичка
От: ArcD  
Дата: 12.03.04 10:08
Оценка:
Здравствуйте, Bell, Вы писали:

B>Итак, начнем по порядку.

B>Удалене из середины вектора одного элемента можно сделать так:
B>
B>int i = ...//позиция удаления
B>list.erase(list.begin() + i);
B>


B>Однако это приводит к тому, что все элементы контейнера, располагавшиеся после удаленного элемента, сдвигаются на одну позицию. Поэтому в цикле применять такой метод нельзя (вернее просто так, без доп. исхищрений, нельзя). Кроме того это крайне неэффективно.

B>Судя по твоему коду, для твоей задачи идеально подходит стандартный алгоритм remove_if в связке с erase:


B>
B>#include <vector>
B>#include <algorithm>

B>class pred
B>{
B>   int n_;
B>public:
B>   pred(int n) : n_(n) {}
B>   bool operator() () { return piece.life_time>n_;}
B>};

B>...

B>std::erase(std::remove_if(list.begin(), list.end(), pred(1000)), list.end());
B>




B>ЗЫ

B>Если намерен заняться изучением STL всерьез, то имеет смысл посмотреть в сторону книги C++ Standard Library, The: A Tutorial and Reference<br />
<span class='lineQuote level1'>B&gt;</span>


Спасибо большое.
Re[5]: STL вопрос новичка
От: Аноним  
Дата: 12.03.04 10:12
Оценка: -1
AD>Спасибо большое вот первый способ мне подходит, только вот как удалить элемент из середины векора?

Если требуется удалять элементы из середины вектора, то это однозначно говорит о том, что использовать нужно не вектор, а list или map. Вообще, у меня складывается впечатление, что изучив vector люди радуются его возможностям и перестают что-либо еще изучать и лепят его везде где надо и не надо.
Re[6]: STL вопрос новичка
От: ArcD  
Дата: 12.03.04 10:18
Оценка:
Здравствуйте, Аноним, Вы писали:


AD>>Спасибо большое вот первый способ мне подходит, только вот как удалить элемент из середины векора?


А>Если требуется удалять элементы из середины вектора, то это однозначно говорит о том, что использовать нужно не вектор, а list или map. Вообще, у меня складывается впечатление, что изучив vector люди радуются его возможностям и перестают что-либо еще изучать и лепят его везде где надо и не надо.


Спасибо.
Наверное ты прав в целом... Но это не про меня. Просто я пока про STL почти ничего не знаю. Попробую и map конечно.
Re[6]: STL вопрос новичка
От: Bell Россия  
Дата: 12.03.04 10:30
Оценка:
Здравствуйте, Аноним, Вы писали:


AD>>Спасибо большое вот первый способ мне подходит, только вот как удалить элемент из середины векора?


А>Если требуется удалять элементы из середины вектора, то это однозначно говорит о том, что использовать нужно не вектор, а list или map.


Меня просто убивают подобные категоричные заявления

Ты знаешь, как выглядит структура PIECE, с которой нужно работать?!
Ты знаешь, насколько часто происходит удаление из середины?!
Ты знаешь, насколько важна/неважна скорость произвольного доступа?!
Ты знаешь специфику задачи?! (это я к вопросу о том, что связка vector + remove_if, вполне эффективна, и как нельзя лучше подходит под данную задачу)

Ы?
Любите книгу — источник знаний (с) М.Горький
Re[7]: STL вопрос новичка
От: SWW Россия  
Дата: 12.03.04 10:42
Оценка:
B>Меня просто убивают подобные категоричные заявления

B>Ты знаешь, как выглядит структура PIECE, с которой нужно работать?!

B>Ты знаешь, насколько часто происходит удаление из середины?!
B>Ты знаешь, насколько важна/неважна скорость произвольного доступа?!
B>Ты знаешь специфику задачи?! (это я к вопросу о том, что связка vector + remove_if, вполне эффективна, и как нельзя лучше подходит под данную задачу)

Нет, ничего этого я не знаю. Но именно поэтому нужно было с самого начала упомянуть как минимум три этих контейнера (vector, list и map) и рассказать вкратце об их отличиях и области применения, чтобы человек мог сам выбрать подходящий, а не зацикливаться на одном векторе.
Re[8]: STL вопрос новичка
От: Bell Россия  
Дата: 12.03.04 10:49
Оценка: 1 (1)
Здравствуйте, SWW, Вы писали:

SWW>Нет, ничего этого я не знаю. Но именно поэтому нужно было с самого начала упомянуть как минимум три этих контейнера (vector, list и map) и рассказать вкратце об их отличиях и области применения, чтобы человек мог сам выбрать подходящий, а не зацикливаться на одном векторе.


Ладно, я поленился вчера это сделать — был уже конец рабочего дня, да и прописные истины каждый раз повторять мне тоже лень.
Однако в исходном вопросе была фраза: "...и самое главное обращаться к нужному данному по номеру...". Именно поэтому я посоветовал посмотеть в сторону вектора. Кроме того, я дал ссылку на статью, предоставив автору вопроса дополнительную возможность самому определиться с выбором.
Любите книгу — источник знаний (с) М.Горький
Re[8]: STL вопрос новичка
От: ArcD  
Дата: 12.03.04 11:08
Оценка:
Здравствуйте, SWW, Вы писали:

B>>Меня просто убивают подобные категоричные заявления


B>>Ты знаешь, как выглядит структура PIECE, с которой нужно работать?!

B>>Ты знаешь, насколько часто происходит удаление из середины?!
B>>Ты знаешь, насколько важна/неважна скорость произвольного доступа?!
B>>Ты знаешь специфику задачи?! (это я к вопросу о том, что связка vector + remove_if, вполне эффективна, и как нельзя лучше подходит под данную задачу)

SWW>Нет, ничего этого я не знаю. Но именно поэтому нужно было с самого начала упомянуть как минимум три этих контейнера (vector, list и map) и рассказать вкратце об их отличиях и области применения, чтобы человек мог сам выбрать подходящий, а не зацикливаться на одном векторе.


Спасибо большое всем! Я обязательно попробую и vector и map. С map'ом даже как-то проще выглядит, если в качестве ключа задавать просто DWORD. Я так понимаю получается почти как вектор:


typedef    map<DWORD,HellMeatPiece>    MEATMAP;

extern    MEATMAP    HellMeat;

int    AddMeatToMap(DWORD    num,HellMeatPiece    *meat)
{
    int    res;
    HellMeat[num]=*meat;
    res=HellMeat.size();
    return    res;
}

int    CheckMeatRemove()
{
    DWORD    i,size;

    size=HellMeat.size();
    for (pos=HellMeat.begin(); pos!=HellMeat.end();)
    {
        MeatPiece=pos->second;
        if (pos->second.life_time>20000)
        {
            HellMeat.erase(pos++);
        }
        else
            ++pos;
    }
    return    HellMeat.size();
}


Вроде работает. Вот только не знаю как HellMeat[num] работает? Просто обращается по индексу или производит сложный поиск используя num как ключ?
И если так, то не сильно ли это тормозно?
Re[9]: STL вопрос новичка
От: Кодт Россия  
Дата: 12.03.04 12:21
Оценка: +1
Здравствуйте, ArcD, Вы писали:

AD>Спасибо большое всем! Я обязательно попробую и vector и map. С map'ом даже как-то проще выглядит, если в качестве ключа задавать просто DWORD. Я так понимаю получается почти как вектор:


Если тебе не нужно идентифицировать объект по какому-то ключу (а в твоём примере нигде это не видно), то вместо map можно использовать set или multiset.
Вообще, выбор контейнера определяется тем, какую задачу (задачи) ты решаешь.

AD>Вроде работает. Вот только не знаю как HellMeat[num] работает? Просто обращается по индексу или производит сложный поиск используя num как ключ?


Производит поиск, используя num как ключ.
Внутри мап устроен как двоичное дерево поиска (обычно — красно-чёрное дерево), поэтому время поиска — не более O(log(N)), где N — размер контейнера (количество элементов).

AD>И если так, то не сильно ли это тормозно?


Оценка времени операций над контейнерами
                                     vector                list               deque       map | set
                                  несорт.  сорт.      несорт.  сорт.     несорт.  сорт.      сорт.

доступ к первому элементу               1                    1                  1           log(N)†
доступ к последнему элементу            1                    1                  1           log(N)†
произвольный доступ                     1                    N                  1‡          log(N)
поиск                               N      log(N)            N              N     log(N)   log(N)

удаление спереди                        N                    1                  1           log(N)
удаление сзади                          1                    1                  1           log(N)
удаление из произвольного места         N                    1                  N‡          log(N)

вставка спереди                     N                    1                  1
вставка сзади                      1|N°                  1                  1
вставка в произвольное место        N                    1                  N
вставка в правильную позицию                 N•                 N•                   N•     log(N)

сортировка                       N*log(N)            N*log(N)

° Если зарезервировано достаточно памяти, то O(1). Если нет — будет копирование всего массива
† Вообще, доступ к первому элементу дерева — это спуск от корня до самого низа. Но реализации могут оптимизировать
‡ Зависит от реализации; скорее, там O(N), но коэффициент при асимптотике гаараздо меньше, чем у списка.
• Естественно, складывается из времени поиска и времени вставки. У вектора и дека тормозит вставка, у списка — поиск. Асимптотика берётся по максимуму.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.