Подтвердить что ты не робот

Быстрый способ реализовать pop_front в std::vector

Я использую некоторые классы и несколько служебных методов, которые используют std::vector.

Теперь мне нужно использовать каждый кадр методом pop_front - push_back для одного из этих классов (но все они связаны и работают вместе, поэтому я не могу изменить только один).

Большинство операций выполняются по всем элементам и операциям push_back, поэтому для лучшей работы я должен сделать следующее: разветкить репозиторий этих классов и утилит, спроектировать все и использовать deque или list.

Но это означает много переписывания кода и много тестов, которые заставят меня пропустить крайний срок.

Поэтому мне нужен совет, чтобы написать эффективный pop_front в вектор статического размера (размер не изменится).

Я нашел здесь способ:

template<typename T>
void pop_front(std::vector<T>& vec)
{
   vec.front() = vec.back();
   vec.pop_back();
   vec.front() = vec.back();  // but should this work?
}

И еще одна идея должна быть:

template<typename T>
void pop_front(std::vector<T>& vec, already_allocated_vector vec1)
{
   vec1.clear();
   copy(vec.begin(), vec.end()-1, vec1.begin());
   copy(vec1.begin(), vec1.end(), vec.begin());
}

Что быстрее этих двух решений? Любые другие решения?

4b9b3361

Ответ 1

Я бы ожидал:

template<typename T>
void pop_front(std::vector<T>& vec)
{
    assert(!vec.empty());
    vec.front() = std::move(vec.back());
    vec.pop_back();
}

- самый эффективный способ сделать это, но он не поддерживает порядок элементов в векторе.

Если вам нужно сохранить порядок оставшихся элементов в vec, вы можете сделать:

template<typename T>
void pop_front(std::vector<T>& vec)
{
    assert(!vec.empty());
    vec.erase(vec.begin());
}

Это будет иметь линейное время в количестве элементов в vec, но это лучшее, что вы можете сделать, не меняя структуру данных.

Ни одна из этих функций не будет поддерживать vector с постоянным размером, так как операция pop_front будет по определению удалять элемент из контейнера.

Ответ 2

Так как pop_front() только стирает первый элемент, прямая реализация такова:

template <typename V>
void pop_front(V & v)
{
    assert(!v.empty());
    v.erase(v.begin());
}

Не беспокойтесь о скорости на данный момент. Если вы хотите вернуться и оптимизировать код, запросите выделенное время проекта.

Ответ 3

Вы также можете использовать IgushArray (https://github.com/igushev/IgushArray), который, как и массив, имеет быстрый доступ к постоянному времени, но операция вставки/стирания только O (N ^ 1/2). Итак, в вашем случае здесь будет очень полезно вставить начало в начало. Будьте осторожны, структура очень чувствительна к резервному().

template <class T>
void pop_front(IgushArray<T>& v)
{
  if (!v.empty())
    v.erase(v.begin());
}

В первом варианте вы написали, что вы нарушаете порядок элементов. Это проблема?

Если это так, используйте вариант, который я написал.

Если нет и порядок элементов вообще не имеет значения, может быть лучше использовать std:: set или std:: multiset.

Ответ 4

если вы просто попытаетесь стереть первый элемент, а затем в функции:

if (my_vector.size()){ //check if there any elements in the vector array
    my_vector.erase(my_vector.begin()); //erase the firs element
}

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

reverse(my_vector.begin(),my_vector.end());  // reverse the order of the vector array
my_vector.pop_back();   // now just simple pop_back will give you the results

Ответ 5

У меня тоже есть способ... Не так хорошо, хотя..

Это похоже на решение @0xPwn, но он не повернул вектор во второй раз. Возможно, вы поймете этот код, поэтому я не буду его объяснять.

#include <algorithm>
#include <vector>
template <typename T>
void pop_front(std::vector<T>& vec){
    std::reverse(vec.begin(),vec.end()); // first becomes last, reverses the vector
    vec.pop_back(); // pop last
    std::reverse(vec.begin(),vec.end()); // reverses it again, so the elements are in the same order as before

}