美文网首页
QT 容器及遍历

QT 容器及遍历

作者: YBshone | 来源:发表于2017-04-09 22:58 被阅读0次

    QT容器遍历分为Java和STL遍历

    STL风格遍历器的语法类似于使用指针对数组的操作。我们可以使用++和--运算符使遍历器移动到下一位置,遍历器的返回值是指向这个元素的指针。例如QVector<T>的iterator返回值是 T *类型,而const_iterator返回值是 const T * 类型(数据为常量,返回值不能修改)。

    一个典型的使用STL风格遍历器的代码是:

    QList<double>::iterator i = list.begin(); 
    while (i != list.end()) { 
           *i = qAbs(*i); 
           ++i; 
    }
    

    对于某些返回容器的函数而言,如果需要使用STL风格的遍历器,我们需要建立一个返回值的拷贝,然后再使用遍历器进行遍历。如下面的代码所示:

    QList<int> list = splitter->sizes(); 
    QList<int>::const_iterator i = list.begin(); 
    while (i != list.end()) { 
            doSomething(*i); 
            ++i; 
    }
    

    在C++中,很多人都会说,要避免这么写,因为最后一个return语句会进行临时对象的拷贝工作。如果这个对象很大,这个操作会很昂贵。所以,资深的C++高手们都会有一个STL风格的写法:

    void sineTable(std::vector<double> &vect)    
    {    
                    vect.resize(360);    
                    for (int i = 0; i < 360; ++i)    
                                    vect[i] = std::sin(i / (2 * M_PI));    
    } 
    // call 
    QVector<double> v; 
    sineTable(v);
    

    这种写法通过传入一个引用避免了拷贝工作。但是这种写法就不那么自然了。而隐式数据共享的使用让我们能够放心的按照第一种写法书写,而不必担心性能问题。

    Qt所有容器类以及其他一些类都使用了隐式数据共享技术,这些类包括QByteArray, QBrush, QFont, QImage, QPixmap和QString。这使得这些类在参数和返回值中使用传值方式相当高效。

    不过,为了正确使用隐式数据共享,我们需要建立一个良好的编程习惯。这其中之一就是,对list或者vector使用at()函数而不是[]操作符进行只读访问。原因是[]操作符既可以是左值又可以是右值,这让Qt容器很难判断到底是左值还是右值,而at()函数是不能作为左值的,因此可以进行隐式数据共享。另外一点是,对于begin(),end()以及其他一些非const容器,在数据改变时Qt会进行深复制。为了避免这一点,要尽可能使用const_iterator, constBegin()和constEnd().

    最后,Qt提供了一种不使用遍历器进行遍历的方法:foreach循环。这实际上是一个宏,使用代码如下所示:

    QLinkedList<Movie> list; 
    Movie movie; 
    ... 
    foreach (movie, list) { 
           if (movie.title() == "Citizen Kane") { 
                   std::cout << "Found Citizen Kane" << std::endl; 
                   break; 
           } 
    }
    

    Qt容器类之关联存储容器

    Qt提供两种关联容器类型:QMap<K, T>和QHash<K, T>。

    QMap<K, T>是一种键-值对的数据结构,它实际上使用跳表skip-list实现,按照K进行升序的方式进行存储。使用QMap<K, T>的insert()函数可以向QMap<K, T>中插入数据,典型的代码如下:

    QMap<QString, int> map; 
    map.insert("eins", 1); 
    map.insert("sieben", 7); 
    map.insert("dreiundzwanzig", 23);
    

    同样,QMap<K, T>也重载了[]运算符,你可以按照数组的复制方式进行使用:

    map["eins"] = 1; 
    map["sieben"] = 7; 
    map["dreiundzwanzig"] = 23;
    
    int val = map.value("dreiundzwanzig");
    

    遍历关联存储容器的最简单的办法是使用Java风格的遍历器。因为Java风格的遍历器的next()和previous()函数可以返回一个键-值对,而不仅仅是值,例如:

    QMap<QString, int> map; 
    ... 
    int sum = 0; 
    QMapIterator<QString, int> i(map); 
    while (i.hasNext()) 
           sum += i.next().value();
    

    如果我们并不需要访问键-值对,可以直接忽略next()和previous()函数的返回值,而是调用key()和value()函数即可,如:

    QMapIterator<QString, int> i(map); 
    while (i.hasNext()) { 
           i.next(); 
           if (i.value() > largestValue) { 
                   largestKey = i.key(); 
                   largestValue = i.value(); 
           } 
    }
    

    Mutable遍历器则可以修改key对应的值:

    QMutableMapIterator<QString, int> i(map); 
    while (i.hasNext()) { 
           i.next(); 
           if (i.value() < 0.0) 
                   i.setValue(-i.value()); 
    }
    

    如果是STL风格的遍历器,则可以使用它的key()和value()函数。而对于foreach循环,我们就需要分别对key和value进行循环了:

    QMultiMap<QString, int> map; 
    ... 
    foreach (QString key, map.keys()) { 
           foreach (int value, map.values(key)) { 
                   doSomething(key, value); 
           } 
    } 
    

    相关文章

      网友评论

          本文标题:QT 容器及遍历

          本文链接:https://www.haomeiwen.com/subject/vsvdattx.html