2016-08-30 11 views
17

Mam następujący kod:Jak poprawić te zagnieżdżone pętle

// vector of elements 
vector<Graphic> graphics; 

// vector of indexes of the selected graphic elements 
vector<int> selected_indexes; 

// vector according to which the graphic elements have to be "sorted" and parsed 
vector<short> order; 

for (auto o : order) 
{ 
    for (auto i : selected_indexes) 
    { 
     const auto& g = graphics[i]; 

     if (g.position() == o) 
     { 
      // parse g 
     } 
    } 
} 

Mam wektor elementów niestandardowych, jak również spis elementów, które zostały wybrane, aby być analizowany, ale porządek w które te elementy muszą zostać przeanalizowane, zależy od ich wartości position() według trzeciego wektora.

Czy istnieje sposób na ulepszenie tych zagnieżdżonych pętli, unikanie wielokrotnego powtarzania elementów, które zostaną pominięte, ponieważ ich pozycja nie jest równa aktualnej kolejności?

+0

Ulepszenia, których szukasz, czy to szybkość (czas wykonania), czytelność czy "elegancja"? – Niall

+0

@Niall Szukam ulepszeń prędkości. – Nick

Odpowiedz

13

Zakładając, że jest tylko jedna Graphic obiekt o danym position():

Zbuduj unordered_map: intGraphics*, że zadzwonisz na przykład gp, dzięki czemu gp[i]->position() = i.

Tworzenie mapy to czas liniowy, a użycie jej dla każdego indeksu to czas stały, w przybliżeniu.

for(auto o : order) 
{ 
    auto const& g = *gp[o]; 
    // parse g 
} 

Jeśli nie może być więcej niż jeden Graphics obiekt o danej pozycji, budować unordered_map: intvector<Graphic*>, następnie z kodem użytkowania jak

for(auto o : order) 
{ 
    for(auto const p : gp[o]) 
    { 
     auto const& g = *p; 
     // parse g 
    } 
} 

albo na tym ostatnim przypadku można użyć unordered_multimap.

+0

Naiwne budowanie mapy jest liniowe pod względem liczby elementów graficznych. Kod OP to O (MN), ale M to wielkość wyboru, a N to wielkość zamówienia, to O (1) w liczbie grafik. Hm: podczas budowania buduj z wektora tylko wybranych indeksów. To doprowadza cię do O (M + N)? Tak. – Yakk

+1

O-Notation to nie wszystko w C++. W zależności od rozmiaru z wektorem i jego sortowania, a następnie iteracja może być szybsza niż iteracja ogromnej mapy. – Hayt

3

Wiesz już, ile elementów ma zostać przetworzona, dzięki czemu można używać wektor, który utrzymuje wskaźniki do swoich Graphic przypadkach już przydzielonych z odpowiednią ilość elementów:

vector<Graphic*> selected(selected_indexes.size(), nullptr); 

Następnie można wypełnić ten wektor z elementów, sortowane przy użyciu order:

for (auto index: selected_indexes) { 
    auto where = std::find_if(order.begin(), order.end(), [&graphics, index] (short i) { return i == graphics[index].position(); }); 
    selected[*where] = &graphics[index]; 
} 
3

Zamiast gniazdowania te można utworzyć tymczasowy wektor i zrobić to krok po kroku.

vector<Graphic> selectedGraphics; //maybe use ptr here 
selectedGraphics.reserve(selected_indexes.size()); 
for(auto i : selected_indexes) 
    selectedGraphics.push_back(graphics[i]); 

//then sort according to your order 
std::sort(selectedGraphics.begin(),selectedGraphics.end(),[order](auto left, auto right) 
{ 
    //the iterator of the position of "left" is further in front of the position of "right" 
    return order.find(left.position()) < order.find(right.position()); 
}); 

//then process 
for(auto graphic : selectedGraphics) 
    //do whatever 

Sortowanie zakłada, że ​​order wpisy wektorowe i te, które są selectedGraphics mecz. Nie jestem pewien, czy wystąpią jakieś dziwne efekty uboczne, jeśli wybrany obiekt graficzny ma pozycję, która nie znajduje się w wektorze order.

+0

Czy możesz rozszerzyć procedurę sortowania? (Przykład kolejności wektorów {2, 1, 3, 0, 4, 5}). – Nick

+1

OK Edytowałem odpowiedź. To powinno działać w ten sposób. Nie mogę tego przetestować. – Hayt

+0

Dodałem też "rezerwę" ze względu na kompletność. – Hayt