Задание:
В этой задаче вам нужно написать структуру, которая будет работать как обычный массив в C и как список в Python. А именно, напишите структуру
template<typename T> struct FlexArray;Те. это шаблонная структура. Это массив элементов типа
Tфиксированной длины, длина передается в конструктор. По умолчанию следует считать, что длина равна 0. (Это не обязывает вас использовать при реализации только классические массивы)Доступ к элементам осуществляется через метод
at(unsigned int index)— возвращает индексный элемент массива. Напишите этот метод правильно как для неконстантных, так и для константных структур. А именно, вызовat(i)для константных структур не должен допускать изменения содержимого массива и, более того, не может появляться слева от знака=.Size(), который возвращает текущий размер массива.
Теперь самое интересное.
Напишите
operator+из двухFlexArraysиoperator+=, где добавлениеFlexArrayсчитается конкатенацией их элементов. Те.{1, 3, 5} + {2, 4} = {1, 3, 5, 2, 4}.Вы можете добавить два разных
FlexArrays, только если их аргументы шаблона совпадают.
operator +=должен фактически добавить новый массив к текущемуFlexArray.Также напишите
operator*иoperator*=отFlexArrayи числаk > 0, где умножение на числоk— это объединение самого себяkраз. Те.{1, 2} * 3 = {1, 2, 1, 2, 1, 2}. Мы можем предположить, чтоk— этоunsigned longУмножать нужно как слева направо, так и справа налево. Те. Возможны только 3 варианта
FlexArray *= k,FlexArray * k,k * FlexArrayint main() { FlexArray<int> flex(3); flex.at(0) = 1; flex.at(1) = 2; flex.at(2) = 3; std::cout << flex.Size(); // 3 auto prod = flex * 2; for (int i = 0; i < prod.Size(); ++i) { std::cout << prod.at(i) << " "; } std::cout << "\n"; // Should output 1 2 3 1 2 3 FlexArray<int> last(2); last.at(0) = 4; last.at(1) = 5; flex += last; for (int i = 0; i < flex.Size(); ++i) { std::cout << flex.at(i) << " "; } std::cout << "\n"; // Should output 1 2 3 4 5 }Итак, реализация этих методов зависит от вас; типы возвращаемых значений здесь специально не прописаны:
FlexArray<T>::FlexArray(); FlexArray<T>::FlexArray(size_t); FlexArray<T>::at(size_t); FlexArray<T>::Size(); FlexArray<T>::operator += (const FlexArray&); FlexArray<T>::operator *= (size_t); operator+(const FlexArray<T>&, const FlexArray<T>&); operator*(const FlexArray<T>&, size_t); operator*(size_t, const FlexArray<T>&);Отправьте в систему только код структуры + возможно необходимо # include
Это мое решение:
template<typename T>
struct FlexArray {
std::vector<T> vec;
FlexArray();
FlexArray(size_t n);
T& at(size_t index);
const T& at(size_t index) const;
size_t Size() const;
FlexArray& operator += (const FlexArray& another);
FlexArray& operator *= (size_t k);
};
template<typename T>
FlexArray<T>::FlexArray() : vec(0){}
template<typename T>
FlexArray<T>::FlexArray(size_t n) : vec(n) {}
template<typename T>
T& FlexArray<T>::at(size_t index) {
return vec[index];
}
template<class T>
const T& FlexArray<T>::at(size_t index) const {
return vec[index];
}
template<typename T>
size_t FlexArray<T>::Size() const{
return vec.size();
}
template<typename T>
FlexArray<T>& FlexArray<T>::operator += (const FlexArray& another) {
for (size_t i = 0; i < another.Size(); i++) {
vec.push_back(another.at(i));
}
return *this;
}
template<typename T>
FlexArray<T>& FlexArray<T>::operator *= (size_t k) {
auto copy = *this;
for (size_t i = 1; i < k; i++) {
*this += copy;
}
return *this;
}
template<typename T>
FlexArray<T> operator+(const FlexArray<T>& left, const FlexArray<T>& right) {
auto copy = left;
copy += right;
return copy;
}
template<typename T>
FlexArray<T> operator*(const FlexArray<T>& arr, size_t k) {
auto copy = arr;
copy *= k;
return copy;
}
template<typename T>
FlexArray<T> operator*(size_t k, const FlexArray<T>& arr) {
return arr * k;
}
Проблема в том, что он не проходит тест памяти (ограничение 64 МБ). Мой код выдает 100мс/86,77Мб.
В системе тестирования используется G++17 7.3.
Как я могу это оптимизировать? (задание взято из онлайн-курса и я уверен, что код можно как-то оптимизировать не очень сложно, или я где-то ошибся)
Примечание по использованию. Возможно, вам не придется предоставлять инструктору полную программу, но если вы ожидаете, что добровольцы помогут отладить ваш код, в ваших интересах предоставить полную программу. Если людям придется превратить ваши фрагменты кода в работоспособный пример, чтобы они могли с ним поэкспериментировать, многие просто уйдут. Некоторые из них, выходя за дверь, проголосуют против и принудительно, потому что вопрос неполный. Те, кто останется и создаст работоспособный пример, могут случайно исправить ошибку в процессе и уйти, поскольку у вас явно нет проблем, а другие могут вставить новые проблемы и сообщить о них.
Пожалуйста, предоставьте минимально воспроизводимый пример.





Использование push_back() в цикле не является эффективным способом объединения двух векторов. Вместо этого используйте vector::insert(), например:
template<typename T>
FlexArray<T>& FlexArray<T>::operator += (const FlexArray& another) {
vec.insert(vec.end(), another.vec.begin(), another.vec.end());
return *this;
}
Кроме того, перед выполнением конкатенации используйте vector::reserve(), чтобы предварительно выделить память для нового размера, например:
template<typename T>
FlexArray<T>& FlexArray<T>::operator *= (size_t k) {
if (k > 1) {
auto copy = *this;
vec.reserve(vec.size() * k);
for (size_t i = 1; i < k; i++) {
*this += copy;
}
} else if (k == 0) {
vec.clear();
}
return *this;
}
template<typename T>
FlexArray<T> operator+(const FlexArray<T>& left, const FlexArray<T>& right) {
FlexArray<T> copy;
copy.vec.reserve(left.Size() + right.Size());
copy += left;
copy += right;
return copy;
}
Альтернативно, манипулируйте vector напрямую, чтобы избежать ненужных копий, как copy в operator *= выше, например:
template<typename T>
FlexArray<T>& FlexArray<T>::operator += (const FlexArray& another) {
size_t oldSize = vec.size();
vec.resize(oldSize + another.Size());
std::copy(another.vec.begin(), another.vec.end(), vec.begin()+oldSize);
return *this;
}
template<typename T>
FlexArray<T>& FlexArray<T>::operator *= (size_t k) {
if (k > 1) {
size_t oldSize = vec.size();
vec.resize(oldSize * k);
for(size_t i = 0; i < oldSize; ++i) {
for (size_t j = 1; j < k; ++j) {
vec[i+(oldSize*j)] = vec[i];
}
}
}
else if (k == 0) {
vec.clear();
}
return *this;
}
template<typename T>
FlexArray<T> operator+(const FlexArray<T>& left, const FlexArray<T>& right) {
FlexArray<T> copy(left.Size() + right.Size());
std::copy(left.vec.begin(), left.vec.end(), copy.vec.begin());
std::copy(right.vec.begin(), right.vec.end(), copy.vec.begin()+left.Size());
return copy;
}
template<typename T>
FlexArray<T> operator*(const FlexArray<T>& arr, size_t k) {
FlexArray<T> copy(arr.Size()*k);
auto iter = copy.vec.begin();
for(size_t i = 0; i < k; ++i) {
std::copy(arr.vec.begin(), arr.vec.end(), iter);
iter += arr.Size();
}
return copy;
}
Возможно, политика изменения размера
vectorвас подводит. Когдаvectorнеобходимо перераспределить для увеличения емкости, размер обычно увеличивается где-то между 1,5 и 2, в зависимости от реализацииvector. На несколько мгновений размер хранилища данных изменяется, а в памяти появляется новое хранилище данных, размер которого в 1,5–2 раза превышает размер оригинала.