我看到qCopy和qCopybackward,但似乎都没有让我按相反顺序复制。 qCopybackward
仅以相反的顺序复制它,但保持darn元素的顺序相同!我想要做的就是以相反的顺序返回列表的副本。那里有 的功能,对吧?
答案 0 :(得分:30)
如果您不喜欢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());
但是我觉得索引摆弄的东西更适合工作保障:)
答案 1 :(得分:20)
用一行反转您的QList:
for(int k = 0; k < (list.size()/2); k++) list.swap(k,list.size()-(1+k));
答案 2 :(得分:9)
您可以使用Java样式迭代器。这里有完整的例子(http://doc.qt.digia.com/3.2/collection.html)。寻找“反向”一词。
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();
}
答案 3 :(得分:8)
@Marc Jentsch的回答很好。如果你想获得额外的 30%的性能提升,你可以将他的单行改为:
for(int k=0, s=list.size(), max=(s/2); k<max; k++) list.swap(k,s-(1+k));
一个QPad为1000万QTimers的ThinkPad W520我得到了这些数字:
提升是
的结果答案 4 :(得分:7)
[原件改写]
目前尚不清楚OP是否想知道“我如何反转QList?”或者实际上想要反转副本。用户mmutz给出了反向拷贝的正确答案,但是如果你只想反转QList,那就是:
#include <algorithm>
然后
std::reverse(list.begin(), list.end());
或者在C ++ 11中:
std::reverse(std::begin(list), std::end(list));
C ++标准库(以及一般模板)的优点在于算法和容器是分开的。起初,标准容器(以及较小程度上的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
的前7个元素?”:即使QList
作者给了我们方便.reverse()
方法,他们可能也不会给出我们这个功能,但在这里:
if (list.size() >= 7) {
std::reverse(std::begin(list), std::advance(std::begin(list), 7));
}
但它变得更好:因为迭代器接口与C指针语法相同,并且因为C ++ 11添加了免费的std::begin()
和std::end
函数,所以你可以这样做:
“你如何反转数组float x[10]
?”:
std::reverse(std::begin(x), std::end(x));
或预C ++ 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));
另请注意,这些都应该与手写循环一样好,因为在可能的情况下,编译器会将这些转换为指针算法。此外,您无法干净地编写像C这样的可重用,通用,高性能reverse
函数。
答案 5 :(得分:5)
对于标准库列表,它看起来像这样
std::list<X> result;
std::copy(list.rbegin(), list.rend(), result.back_inserter());
不幸的是,Qt没有返回反向迭代器的rbegin和rend函数(从容器的末尾到它的begnning)。您可以编写它们,或者您可以自己编写复制功能 - 反转列表是一个很好的例外。或者您可以注意到QList实际上是一个数组,这使得编写这样一个函数变得微不足道。或者您可以将列表转换为std :: list,并使用rbegin和rend。选择你喜欢的任何东西。
答案 6 :(得分:5)
反转QList将是O(n)然而你这样做,因为不保证QList将其数据连续存储在内存中(与QVector不同)。您可以考虑在需要的地方以向后的顺序遍历列表,或者使用类似QStack的东西,它允许您按照添加的相反顺序检索元素。