Jaki jest najskuteczniejszy sposób uzyskania indeksu iteratora std:: vector?

Iteruję nad wektorem i potrzebuję indeksu, na który aktualnie wskazuje iterator. AFAIK można to zrobić na dwa sposoby:

  • it - vec.begin()
  • std::distance(vec.begin(), it)

Jakie są plusy i minusy tych metod?

10 answers

Wolałbym it - vec.begin() właśnie z przeciwnego powodu podanego przez naveena: więc nie skompilowałby się, jeśli zmienisz wektor w listę. Jeśli zrobisz to podczas każdej iteracji, możesz łatwo przekształcić algorytm O(n) W algorytm O(N^2).

Inną opcją, jeśli nie przeskakujesz w kontenerze podczas iteracji, byłoby zachowanie indeksu jako licznika drugiej pętli.

Uwaga: {[1] } jest potoczną nazwą iteratora kontenera, std::container_type::iterator it;.

 596
Author: UncleBens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-30 22:35:44

Wolałbym std::distance(vec.begin(), it), ponieważ pozwoli mi to na zmianę kontenera bez żadnych zmian kodu. Na przykład, jeśli zdecydujesz się użyć std::list zamiast std::vector, który nie zapewnia losowego iteratora dostępu, Twój kod nadal będzie kompilowany. Ponieważ STD:: distance wybiera optymalną metodę w zależności od cech iteratora, nie będziesz mieć również żadnego pogorszenia wydajności.

 140
Author: Naveen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-28 07:46:20

UncleBens i Naveen pokazali, że istnieją dobre powody dla obu. Które z nich jest "lepsze" zależy od tego, jakie zachowanie chcesz: czy chcesz zagwarantować zachowanie w stałym czasie, czy chcesz, aby w razie potrzeby spaść z powrotem do czasu liniowego?

it - vec.begin() zajmuje stały czas, ale operator - jest definiowany tylko na iteratorach dostępu losowego, więc kod nie będzie kompilowany z iteratorami listy, na przykład.

std::distance(vec.begin(), it) działa dla wszystkich typów iteratorów, ale będzie działać tylko w czasie stałym jeśli jest używany na iteratorach dostępu losowego.

Żadne z nich nie jest "lepsze". Użyj tego, który robi to, czego potrzebujesz.
 75
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-01 12:21:19

Podoba mi się ten: it - vec.begin(), ponieważ dla mnie wyraźnie mówi "odległość od początku". Z iteratorami jesteśmy przyzwyczajeni do myślenia w kategoriach arytmetyki, więc znak - jest tutaj najczystszym wskaźnikiem.

 11
Author: Eli Bendersky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-28 07:46:12

Jeśli masz już ograniczony / zakodowany na twardo algorytm do używania tylko std::vector::iterator i std::vector::iterator, nie ma znaczenia, która metoda zostanie użyta. Twój algorytm jest już skonkretyzowany poza punktem, w którym wybór jednego z nich może zrobić dowolną różnicę. Oboje robią dokładnie to samo. To tylko kwestia osobistych preferencji. Osobiście użyłbym wyraźnego odejmowania.

Jeśli natomiast chcesz zachować wyższy stopień ogólności w algorytmie, mianowicie, aby umożliwić możliwość, że pewnego dnia w przyszłości może być zastosowana do innego typu iteratora, wtedy najlepsza metoda zależy od twoich intencji. To zależy od tego, jak restrykcyjne chcesz być w odniesieniu do typu iteratora, który może być używany tutaj.

  • Jeśli użyjesz jawnego odejmowania, Twój algorytm będzie ograniczony do raczej wąskiej klasy iteratorów: iteratorów o dostępie losowym. (To jest to, co dostajesz teraz z std::vector)

  • Jeśli używasz distance, algorytm będzie obsługiwał znacznie szerszą klasę iteratorów: Iteratory wejściowe.

Oczywiście, obliczanie distance dla iteratorów bez dostępu losowego jest w ogólnym przypadku operacją nieefektywną (podczas gdy, PONOWNIE, dla iteratorów z dostępem losowym jest równie wydajne jak odejmowanie). To do ciebie należy decyzja, czy twój algorytm ma sens dla iteratorów bez dostępu losowego, pod względem wydajności. Wynikająca z tego utrata wydajności jest niszczycielska do tego stopnia, że Twój algorytm jest całkowicie bezużyteczne, to lepiej trzymać się odejmowania, tym samym zakazując nieefektywnych zastosowań i zmuszając użytkownika do poszukiwania alternatywnych rozwiązań dla innych typów iteratorów. Jeśli wydajność z iteratorami dostępu losowego jest nadal w zasięgu, powinieneś użyć distance i udokumentować fakt, że algorytm działa lepiej z iteratorami dostępu losowego.

 10
Author: AnT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-03 19:14:06

Zgodnie z http://www.cplusplus.com/reference/std/iterator/distance / , ponieważ vec.begin() jest iteratorem dostępu losowego, metoda odległości używa operatora -.

Więc odpowiedź jest taka sama, z punktu widzenia wydajności, ale może użycie distance() jest łatwiejsze do zrozumienia, jeśli ktoś będzie musiał przeczytać i zrozumieć Twój kod.

 4
Author: Stéphane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-28 07:46:52

Użyłbym wariantu - tylko dla std::vector - jest całkiem jasne, co to znaczy, a prostota operacji (która nie jest więcej niż odejmowaniem wskaźnika) jest wyrażona przez składnię (distance, z drugiej strony, brzmi jak Pitagoras w pierwszym czytaniu, prawda?). Jak wskazuje UncleBen, - działa również jako twierdzenie statyczne w przypadku, gdy vector zostanie przypadkowo zmieniona na list.

Również myślę, że jest to o wiele bardziej powszechne - nie mają liczby, aby to udowodnić, choć. Argument Główny: it - vec.begin() jest krótszy w kodzie źródłowym - mniej pisania, mniej miejsca. Ponieważ jest jasne, że właściwa odpowiedź na twoje pytanie sprowadza się do kwestii gustu, może to również być ważnym argumentem.

 3
Author: Alexander Gessler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-03 18:50:29

Oto przykład, aby znaleźć" wszystkie " wystąpienia 10 wraz z indeksem. Pomyślałem, że to pomoże.

void _find_all_test()
{
    vector<int> ints;
    int val;
    while(cin >> val) ints.push_back(val);

    vector<int>::iterator it;
    it = ints.begin();
    int count = ints.size();
    do
    {
        it = find(it,ints.end(), 10);//assuming 10 as search element
        cout << *it << " found at index " << count -(ints.end() - it) << endl;
    }while(++it != ints.end()); 
}
 0
Author: Srikanth Batthula,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-26 05:40:24

Właśnie odkryłem to: https://greek0.net/boost-range/boost-adaptors-indexed.html

    for (const auto & element : str | boost::adaptors::indexed(0)) {
        std::cout << element.index()
                  << " : "
                  << element.value()
                  << std::endl;
    }

 0
Author: Spongman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-24 19:04:07

Obok int float string itd., można umieścić dodatkowe dane do .drugi przy użyciu diff. typ:

std::map<unsigned long long int, glm::ivec2> voxels_corners;
std::map<unsigned long long int, glm::ivec2>::iterator it_corners;

Lub

struct voxel_map {
    int x,i;
};

std::map<unsigned long long int, voxel_map> voxels_corners;
std::map<unsigned long long int, voxel_map>::iterator it_corners;

Kiedy

long long unsigned int index_first=some_key; // llu in this case...
int i=0;
voxels_corners.insert(std::make_pair(index_first,glm::ivec2(1,i++)));

Lub

long long unsigned int index_first=some_key;
int index_counter=0;
voxel_map one;
one.x=1;
one.i=index_counter++;

voxels_corners.insert(std::make_pair(index_first,one));

Z odpowiednim typem / / struktury można umieścić wszystko w .drugi zawiera numer indeksu, który jest zwiększany podczas wstawiania.

Zamiast

it_corners - _corners.begin()

Lub

std::distance(it_corners.begin(), it_corners)

Po

it_corners = voxels_corners.find(index_first+bdif_x+x_z);

Indeks jest po prostu:

int vertice_index = it_corners->second.y;

Przy użyciu typu GLM:: ivec2

Lub

int vertice_index = it_corners->second.i;

W przypadek typu danych struktury

 0
Author: Gerard Wensink,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-29 20:22:47