摘要
在Qt库中为我们提供了一系列的基于模板的容器类。这些类可以被用来存储特定类型的项。这些容器类都是隐式共享的,可重入的,并且在速度上进行了优化,内存占用少,内联代码扩展少,从而可以产生更小的可执行文件。此外,当他们被用作只读容器时,还是线程安全的。
一、常见容器类
在开发一个较高性能需求的应用程序时,程序员会比较关注这些容器类的运
行效率,表2.1列出了QList、QLinkedList和QVector容器 的时间复杂度比较。
容器类 | 查找 | 插入 | 头部添加 | 尾部添加 |
---|---|---|---|---|
QList | O(1) | O(n) | Amort.O(1) | Amort.O(1) |
QLinkedList | O(n) | O(1) | O(1) | O(1) |
QVector | O(1) | O(n) | O(n) | Amort.O(1) |
二、QList类、 QLinkedList 类和QVector类
1、QList类
QList是迄今为止最常用的容器类,它存储给定数据类型T的一列数值。
QList不仅提供了可以在列表进行追加的QList::append()和list::prepend()函数,还提供了在列表中间完成插入操作的函数QList:insert()。
QList维护了一个指针数组,该数组存储的指针指向QList存储的列表项的内容。
对于不同的数据类型,QList采取不同的存储策略,存储策略有以下几种。
(1)如果T是一个指针类型或指针大小的基本类型(即该基本类型占有的字节数和指针类型占有的字节数相同),QList 会将数值直接存储
在它的数组中。
(2)如果QList存储对象的指针,则该指针指向实际存储的对象。
相关例子:
#include <QDebug>
int main(int argc,char *argv[])
{
QList<QString>list;
{
QString str("This is a test string");
list<<str;
}
qDebug()<<list[0]<<"How are you!";
return 0;
}
2. QLinkedList类
QLinkedList是一个链式列表,它以非连续的内存块保存数据。
QLinkedList不能使用下标,只能使用迭代器访问它的数据项。
3. QVector 类
QVector在相邻的内存中存储给定数据类型T的一组数值。
QVector既可以使用下标访问数据项,也可以使用迭代器访问数据项。
4. Java风格迭代器遍历容器
Java风格的迭代器是Qt 4新加入的一个功能。
对于每一个容器类,Qt都提供了两种类型的Java风格迭代器数据类型,即只读访问和读写访问,其分类见下表。
容器类 | 只读迭代器类 | 读写迭代器类 |
---|---|---|
QList,QQueue | QListIterator | QMutableListIterator |
QLinkedList | QLinkedListIterator | QMutableLinkedListIterator |
Qvector,QStack | QVectorIterator | QMutableVectorIterator |
5. STL风格迭代器遍历容器
对于每一个容器类,Qt都提供了两种类型的STL风格迭代器数据类型:一种提供只读访问;另- -种提供读写访问。
三、QMap类和QHash类
QMap类和QHash类具有非常类似的功能,它们的差别仅在于:
●QHash具有比QMap更快的查找速度;
●QHash以任意的顺序存储数据项,而QMap总是按照键Key顺序存储数据;
●QHash的键类型Key必须提供operator==()和一个全局的qHash(Key)函数,
而QMap的键类型Key必须提供operator<()函数。
二者的时间复杂度比较见下表。
容器类 | 键查找 | 插入 |
---|---|---|
平均 | 最坏 | |
QMap | Olog(n) | Olog(n) |
QHash | Amort.O(1) | O(n) |
1. QMap类
QMap<Key,T>提供了一个从类型为Key的键到类型为T的值的映射。
2. QHash类
QHash<Key,T>具有与QMap几乎完全相同的API。QHash维护着一张哈希表(HashTable),哈希表的大小与QHash的数据项的数目相适应。
3. Java风格迭代器遍历容器
对于每一个容器类,Qt都提供了两种类型的Java风格迭代器数据类型:一种提供只读访问;另一种提供读写访问。
下面的例子完成了QMap中的插入、遍历和修改。
#include <QDebug>
int main(int argc,char *argv[])
{
QMap<QString,QString>map;
map.insert("beijing","111");
map.insert("shanghai","021");
map.insert("nanjingjing","025");
QMaplterator<QString,QString>i(map);
for(;i.hasNext();)
qDebug()<<" "<<i.key()<<" "<<i.next().value();
QMutableMaplterator<QString,QString>mi(map);
if(mifindNex(111"))
mi.setValue("010");
QMaplterator<QString,QString> modi(map);
qDebug()<<" ";
for(;modi.hasNext();)
qDebug()<<" "<<modi.key()<<" "<<modi.next().value();
return 0;
}
四、QVariant类
1、QVariant类及QVariant与自定义数据类型转换的方法
这个类型相当于是Java里面的Object,它把绝大多数Qt提供的数据类型都封装起来,起到一个数据类型“擦除”的作用。比如我们的 table
单元格可以是string,也可以是int,也可以是一个颜色值,那么这么多类型怎么返回呢?于是,Qt提供了这个QVariant类型,你可以把这
很多类型都存放进去,到需要使用的时候使用一系列的to函数取出来即可。
比如你把int包装成一个QVariant,使用的时候要用 QVariant::toInt()重新取出来。这里需要注意的是,QVariant类型的放入和取出必须是
相对应的,你放入一个int就必须按int取出,不能用toString(), Qt不会帮你自动转换。数据核心无非就是一个 union,和一个标记类型的
type:传递的是整数 123,那么它union存储整数123,同时type标志Int;如果传递字符串,union存储字符串的指针,同时type标志
QString。
QVariant 属于 Qt 的Core模块,属于Qt的底层核心之一,ActiveQt、QtScript、QtDeclarative等都严重依赖于QVariant。
2、QVariant 可以保存很多Qt的数据类型
QVariant包括QBrush、QColor、QCursor、QDateTime、QFont、QKeySequence、 QPalette、QPen、QPixmap、QPoint、QRect、
QRegion、QSize和QString,并且还有C++基本类型,如 int、float等。QVariant还能保存很多集合类型,
如QMap<QSTRING, QVariant>, QStringList和QList。item view classes,数据库模块和QSettings都大量使用了QVariant类,,以方便
我们读写数据。
3、QVariant也可以进行嵌套存储,例如:
QMap<QString, QVariant> pearMap;
pearMap["Standard"] = 1.95;
pearMap["Organic"] = 2.25;
QMap<QString, QVariant> fruitMap;
fruitMap["Orange"] = 2.10;
fruitMap["Pineapple"] = 3.85;
fruitMap["Pear"] = pearMap;
QVariant被用于构建Qt Meta-Object,因此是QtCore的一部分。当然,我们也可以在GUI模块中使用,例如:
QIcon icon("open.png");
QVariant variant = icon;
// other function
QIcon icon = variant.value<QIcon>();
我们使用了value()模版函数,获取存储在QVariant中的数据。这种函数在非GUI数据中同样适用,但是,在非GUI模块中,我们通常使用
toInt()这样的一系列函数,如toString()等。