Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Usuwanie elementów z std::vector<>

Ostatnio zmodyfikowano 2024-11-12 17:44
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
Usuwanie elementów z std::vector<>
» 2024-11-12 16:53:07
Witam. Mam zbiór obiektów _natures oraz dwa wektory natures, gameObjects na których znajdują się te obiekty. Chciałbym usuąć wszystkie obiekty _natures z wektorów natures oraz gameObjects. Mam już kod ale jest powolny. Da się to przyśpieszyć ?

C/C++
void removeGameObjectsFromMainLists() {
   
// delete _natures from natures and gameObjects
   
for( auto & nature: _natures ) {
       
auto it = std::find( natures.begin(), natures.end(), nature ); // znajdz indeks
       
if( it != natures.end() )
           
 natures.erase( it ); // usun z indeksu
       
       
auto go = std::find( gameObjects.begin(), gameObjects.end(), nature ); // znajdz indeks
       
if( go != gameObjects.end() )
           
 gameObjects.erase( go ); // usun z indeksu
       
   
}
}
P-181901
tBane
Temat założony przez niniejszego użytkownika
» 2024-11-12 17:33:08
Rozwiązanie:

C/C++
for( auto & nature: _natures ) {
   
nature->exist = false;
}

for( int i = natures.size() - 1; i >= 0; i-- )
if( natures[ i ]->exist == false )
   
 natures.erase( natures.begin() + i );

for( int i = gameObjects.size() - 1; i >= 0; i-- )
if( gameObjects[ i ]->exist == false )
   
 gameObjects.erase( gameObjects.begin() + i );

P-181902
pekfos
» 2024-11-12 17:44:13
A skąd wiesz że ta funkcja jest powolna, jeżeli nie wiesz co w tej funkcji jest powolne? Wiesz, Visual ma profiler który pokaże gdzie procesor spędził ile procent czasu.

Jak się ma rozmiar _natures do rozmiaru pozostałych kontenerów?
C/C++
for( auto & nature: _natures ) {
   
auto it = std::find( natures.begin(), natures.end(), nature ); // znajdz indeks
   
if( it != natures.end() )
       
 natures.erase( it ); // usun z indeksu
   
Niech n to rozmiar _natures i N to rozmiar natures. Ten kod ma złożoność O(nN). Dla każdego z n elementów dotykasz każdy z N elementów. Do pewnego punktu wyszukiwaniem, a dalej usuwaniem. Nawet jeżeli zoptymalizujesz wyszukiwanie, masz tu co najmniej pesymistyczne O(n2) w usuwaniu, więc dla dużego n będzie wolno. Dlatego ja bym tu odwrócił pętle i konstruował nowy kontener natures/gameObjects z samych elementów które mają zostać, wtedy wyszukiwanie robimy w małym kontenerze _natures, który na potrzeby tego algorytmu można skopiować do kontenera zoptymalizowanego pod kątem wyszukiwania, np std::set<>, albo std::unordered_set<>.

C/C++
for( int i = gameObjects.size() - 1; i >= 0; i-- )
if( gameObjects[ i ]->exist == false )
   
 gameObjects.erase( gameObjects.begin() + i );
Jak możesz to oczywiście najszybciej jest wewnętrznie oznaczyć obiekty, zamiast robić wyszukiwanie. Natomiast wyobraź sobie N = 100 * n i usuwasz pierwsze n elementów. Złożoność to wtedy O(n*(N-n)) więc dalej kwadratowa w pesymistycznym przypadku. Jeśli tylko możesz, nie usuwaj w pętli obiektów ze środka kontenera bo złożoność będzie słaba. Użyj std::remove_if() i jednego wywołania erase() by usunąć zakres elementów, co da czas liniowy w każdym ułożeniu elementów. std::remove_if() nadpisuje usuwane elementy następnym nieusuniętym elementem, co zostawia wolne miejsce na końcu kontenera, które możesz usunąć w czasie stałym.
P-181903
« 1 »
  Strona 1 z 1