Я вижу qCopy и qCopybackward но ни один из них не позволяет мне сделать копию в обратном порядке. qCopybackward
только копирует его в обратном порядке, но сохраняет элементы штопа в одном порядке! Все, что я хочу сделать, это вернуть копию списка в обратном порядке. Там имеет функцию для этого, правильно?
Как отменить QList?
Ответ 1
Если вам не нравится QTL, просто используйте STL. У них может не быть Qt-ish API, но STL API устойчив к року:) Тем не менее, qCopyBackward
- это просто std::copy_backward
, поэтому, по крайней мере, они совместимы.
Отвечая на ваш вопрос:
template <typename T>
QList<T> reversed( const QList<T> & in ) {
QList<T> result;
result.reserve( in.size() ); // reserve is new in Qt 4.7
std::reverse_copy( in.begin(), in.end(), std::back_inserter( result ) );
return result;
}
РЕДАКТИРОВАТЬ 2015-07-21: Очевидно (или, может быть, нет), если вы хотите использовать один-лайнер (и люди, похоже, предпочитают это, глядя на относительные варианты ответов через пять лет), и у вас есть не const
list
, описанный выше сворачивается на
std::reverse(list.begin(), list.end());
Но я думаю, что материал, работающий с индексом, лучше подходит для безопасности работы:)
Ответ 2
Обрати свой QList с помощью одной строки:
for(int k = 0; k < (list.size()/2); k++) list.swap(k,list.size()-(1+k));
Ответ 3
Вы можете использовать итератор стиля Java. Полный пример здесь (http://doc.qt.digia.com/3.2/collection.html). Найдите слово "reverse".
QList<int> list; // initial list
list << 1;
list << 2;
list << 3;
QList<int> rlist; // reverse list+
QListIterator<int> it(list);
while (it.hasPrevious()) {
rlist << it.previous();
}
Ответ 4
@Marc Jentsch ответ хороший. И если вы хотите получить дополнительный 30% -ный прирост производительности, вы можете изменить его однострочный размер на:
for(int k=0, s=list.size(), max=(s/2); k<max; k++) list.swap(k,s-(1+k));
Один ThinkPad W520 с QList из 10 миллионов QTimers Я получил эти цифры:
- Переполнение стека перевернутого списка заняло 194 мс
- переполнение стека перевернутого списка с максимальным размером и размером 136 мс
Усиление - результат
- выражение (list.size()/2) вычисляется только один раз при инициализации цикла, а не после каждого шага
- выражение list.size() в swap() вызывается только один раз при инициализации цикла, а не после каждого шага
Ответ 5
[Переписать из оригинала]
Не ясно, хочет ли OP знать "Как [изменить] QList?" или на самом деле хочет обратную копию. Пользователь mmutz дал правильный ответ на обратную копию, но если вы просто хотите отменить QList на месте, вот что:
#include <algorithm>
И затем
std::reverse(list.begin(), list.end());
Или в С++ 11:
std::reverse(std::begin(list), std::end(list));
Красота стандартной библиотеки С++ (и шаблонов в целом) заключается в том, что алгоритмы и контейнеры являются отдельными. Сначала может показаться раздражающим, что стандартные контейнеры (и, в меньшей степени, контейнеры Qt) не имеют удобных функций, таких как list.reverse()
, но рассмотрите альтернативы: что более элегантно: Предоставьте методы reverse()
для всех контейнеров, или определить стандартный интерфейс для всех контейнеров, которые позволяют двунаправленную итерацию, и предоставить одну реализацию reverse()
, которая работает для всех контейнеров, поддерживающих двунаправленную итерацию?
Чтобы проиллюстрировать, почему это элегантный подход, рассмотрите ответы на некоторые похожие вопросы:
"Как вы меняете std::vector<int>
?":
std::reverse(std::begin(vec), std::end(vec));
"Как вы меняете std::deque<int>
?":
std::reverse(std::begin(deq), std::end(deq));
Как насчет частей контейнера?
"Как вы отменяете первые семь элементов QList
?": даже если авторы QList
предоставили нам удобный метод .reverse()
, они, вероятно, не предоставили бы нам эту функцию, но здесь это:
if (list.size() >= 7) {
std::reverse(std::begin(list), std::advance(std::begin(list), 7));
}
Но это становится лучше: поскольку интерфейс итератора совпадает с синтаксисом C-указателя, а потому, что С++ 11 добавил бесплатные функции std::begin()
и std::end
, вы можете сделать это:
"Как изменить массив float x[10]
?":
std::reverse(std::begin(x), std::end(x));
или pre С++ 11:
std::reverse(x, x + sizeof(x) / sizeof(x[0]));
(Это уродство, которое std::end()
скрывает для нас.)
Продолжайте:
"Как изменить буфер float* x
размера n
?":
std::reverse(x, x + n);
"Как изменить строку с нулевым завершением char* s
?":
std::reverse(s, s + strlen(s));
"Как изменить строку char* s
в необязательном порядке с нулевым завершением в буфере размера n
?":
std::reverse(s, std::find(s, s + n, '\0'));
Обратите внимание, что std::reverse
использует swap()
, поэтому даже это будет выполняться в значительной степени, а также возможно:
QList<QList<int> > bigListOfBigLists;
....
std::reverse(std::begin(bigListOfBigLists), std::end(bigListOfBigLists));
Также обратите внимание, что все они должны выполняться так же, как и ручной цикл, поскольку, когда это возможно, компилятор превратит их в арифметику указателя. Кроме того, вы не можете четко написать многоразовую, общую, высокопроизводительную функцию reverse
, подобную этой C.
Ответ 6
Для стандартных списков библиотек это будет выглядеть как
std::list<X> result;
std::copy(list.rbegin(), list.rend(), result.back_inserter());
К сожалению, Qt не имеет функций rbegin и rend, которые возвращают обратные итераторы (те, которые идут от конца контейнера к его началу). Вы можете написать их, или вы можете просто написать функцию копирования самостоятельно - реверсирование списка - отличный excersize. Или вы можете заметить, что QList на самом деле является массивом, что делает запись такой функции тривиальной. Или вы можете преобразовать список в std:: list и использовать rbegin и rend. Выберите все, что вам нравится.
Ответ 7
Реверсирование QList будет O (n), но вы это сделаете, поскольку QList не гарантирует, что его данные хранятся в памяти (в отличие от QVector). Вы можете рассмотреть просто перемещение списка в обратном порядке, где вам нужно, или использовать что-то вроде QStack, которое позволяет извлекать элементы в обратном порядке, которые они добавили.