如何反转QList?

时间:2009-08-27 06:07:15

标签: qt

我看到qCopyqCopybackward,但似乎都没有让我按相反顺序复制。 qCopybackward仅以相反的顺序复制它,但保持darn元素的顺序相同!我想要做的就是以相反的顺序返回列表的副本。那里有 的功能,对吧?

7 个答案:

答案 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我得到了这些数字:

  • 倒车列表堆栈溢出需要194毫秒
  • 反转列表堆栈溢出,最大值和大小耗时136 ms

提升是

的结果
  • 表达式(list.size()/ 2)在初始化循环时只计算一次而不是在每一步之后计算
  • swap()中的表达式list.size()只在初始化循环时调用一次而不是在每一步之后调用

答案 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的东西,它允许您按照添加的相反顺序检索元素。