Qt提供了一组通用的基 于模板的容器类。对比C++的标准模板库中的容器类,Qt 的这些容器更轻量、更安全并且更容易使用。
存储在Qt容器中的数据必须是可赋值的数据类型,也就是说,这种数据类型必须提供一个默认的构造函数(不需要参数的构造函数)、一个复制构造函数和一个赋值操作运算符。
这样的数据类型包含了通常使用的大多数数据类型,包括基本数据类型(如int和double等)和Qt的一些数据类型(如QString、 QDate和QTime等)。不过,Qt的QObject及其他的子类(如QWidget和Qdialog等)是不能够存储在容器中的,一个可代替的方案是存储QObject及其子类的指针。
此外Qt的容器类也是可以嵌套的。
Qt的容器类位遍历其中的内容提供了两种方法,一种是Java风格的迭代器,另一种是STL风格的迭代器。
一、QList类、QLinkedList类、QVector类
下图为这三个类的时间复杂度比较:
1、QList类
QList<T>
是迄今为止最常用的容器类,它存储给定数据类型T的一列数值。 继承自QList类的子类有QltemSelection.、QQueue、 QSigalspy、 QStringList 和QTestEventList。
常用的函数有:
QList::append()、QList::prepend():在列表中进行追加。
QList::insert()函数:在列表中进行插入。
QList<T>
维护了一个指针数组,该数组存储的指针指QList<T>
存储的列表项的内容。因此,QList<T>
提供了基于下标的快速访问。
对于不同的数据类型,QList<T>
采取不同的存储策略,存储策略有以下几种。
(1)如果T是一个指针类型或指针大小的基本类型,QList<T>
会将数值直接存储在它的数组中。
(2)如果QList<T>
存储对象的指针。则该指针指向实际存储的对象。
2、QLinkedList类
QLinkedList<T>
是一个链式列表,它以非连续的内存块保存数据。
QLinkedList<T>
不能使用下标,只能使用迭代器访问它的数据项。与QList相比,当对一个很大的列表进行插入操作时,QLinkedList 具有更高的效率。
3、QVector类
QVector<T>
在相邻的内存中存储给定数据类型T的一组数值。在一个QVector的前部或者中间位置进行插入操作的速度是很慢的,这是因为这样的操作将导致内存中的大量数据被移动,这是由QVector存储数据的方式决定的。
QVector<T>
既可以使用下标访问数据项,也可以使用迭代器访问数据项。继承自QVector类的子类有QPolygon、QPolygonF 和QStack。
4、Java风格迭代器遍历容器
下图是两种类型的 Java风格迭代器数据类型
Java风格迭代器的迭代点 位于列表项的中间,而不是直接指向某个列表项。因此,它的迭代点或者在第一个列表项的前面,或者在两个列表项之间,或者在最后一个列表项之后。
下面以QList为例,介绍两种Java风格迭代器的用法。QLinkedlist 和QVector具有与QList相同的遍历接口,在此不再详细讲解。
(1) QList只读遍历方法。
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> list;
list<<1<<2<<3<<4<<5;
QListIterator<int> i(list);
for(;i.hasNext();)
qDebug()<<i.next();
return a.exec();
}
以上是对列表进行前向遍历,后向遍历的函数有:
QListIterator<T>::toBack()
:将迭代点移动到最后一个列表项的后面。
QListIterator<T>::hasPrevious()
:检查当前迭代点之前是否具有列表项。
QListIterator<T>::Previous()
:返回前个列表项的内容并将迭代点移动到前一个列表项之前。
(2) QListIterator<T>
是只读迭代器,它不能完成列表项的插入和删除操作。读写迭代器QMutableListIterator<T>
除提供基本的遍历操作外,还提供了insert()插入,remove()删除操作函数和修改数据函数等。
以下代码为QList读写操作:
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> list;
QMutableListIterator<int> i(list);
for(int j=0;j<10;++j)
i.insert(j);
for(i.toFront();i.hasNext();)
qDebug()<<i.next();
for(i.toBack();i.hasPrevious();)
{
if(i.previous()%2==0)
i.remove();
else
i.setValue(i.peekNext()*10);
}
for(i.toFront();i.hasNext();)
qDebug()<<i.next();
return a.exec();
}
5、STL风格迭代器遍历容器
STL风格迭代器的两种分类如下图所示:
二、QMap类和QHash类
QMap类和QHash类具有非常类似的功能,它们的差别仅在于:
QHash具有比QMap更快的查找速度;
QHash以任意的顺序存储数据项,而QMap总是按照键(Key的顺序存储数据;
QHash的键类型Key必须提供operator==()和一个全局的qHash(Key)函数,而QMap的键类型Key必须提供operator<()函数。
QMap和QHash的时间复杂图如图:
1、QMap类
QMap<Key,T>提供了一个从类型为 Key的键到类型为T的值的映射。
通常,QMap存储的数据形式是一个键对应一个值,并且按照键Key的顺序存储数据。为了能够支持一键多值的情况,QMap提供了QMaps<Key,T>::insertMulti()和QMap<Key,T>::values()函数。存储一键多值的数据时,也可以使用QMultiMap<Key,T>容器,它继承自QMap。
2、QHash 类
QHash<Key,T>具有与QMap几乎完全相同的API。QHash维护着一张哈希表( Hash Table),哈希表的大小与QHash的数据项的数目相适应。
QHash以任意的顺序组织它的数据。当存储数据的顺序无关紧要时,建议使用QHash作为存放数据的容器。QHash也可以存储一键多值形式的数据,它的子类QMultiHash<Key,T>实现了一键多值的语义。
3. Java 风格迭代器遍历容器
Java风格迭代器的两种分类如下图所示:
下面举一个例子,包含在QMap中的插入、遍历和修改,如下代码:
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<QString,QString> map; //创建一个QMap栈对象
//向栈对象插入<城市,区号>对
map.insert("beijing","111");
map.insert("shanghai","021");
map.insert("nanjing","025");
QMapIterator<QString,QString> i(map); //创建一个只读迭代器
for(;i.hasNext();)
qDebug()<<" "<<i.key()<<" "<<i.next().value();
QMutableMapIterator<QString,QString> mi(map);
if(mi.findNext("111"))
mi.setValue("010");
QMapIterator<QString,QString> modi(map);
qDebug()<<" ";
for(;modi.hasNext();) //再次遍历并输出修改后的结果
qDebug()<<" "<<modi.key()<<" "<<modi.next().value();
return a.exec();
}
4、STL风格迭代器遍历容器
STL风格迭代器的两种分类如下图所示:
三、QVariant类
QVariant类类似于C++的联合(union) 数据类型,它不仅能保存很多Qt 类型的值,包括QColor、QBrush、 QFont、QPen、QRect、QString 和QSize等,而且也能存放Qt的容器类型的值。Qt的很多功能都是建立在QVariant基础上的,如Qt的对象属性及数据库功能等。
下面我们用一个例子介绍这个类的具体用法:
#include "widget.h"
#include <QDebug>
#include <QVariant>
#include <QColor>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QVariant v(709); //声明QVariant变量v
qDebug()<<v.toInt(); //将变量包含的内容转换为整数并输出
QVariant w("How are you! "); //声明一个QVariant变量w
qDebug()<<w.toString(); //将w包含的内容转换为字符串并输出
QMap<QString,QVariant>map;
map["int"]=709; //输入整数型
map["double"]=709.709; //输入浮点型
map["string"]="How are you! "; //输入字符串
map["color"]=QColor(255,0,0); //输入QColor类型的值
//调用相应的转换函数并输出
qDebug()<<map["int"]<< map["int"].toInt();
qDebug()<<map["double"]<< map["double"].toDouble();
qDebug()<<map["string"]<< map["string"].toString();
qDebug()<<map["color"]<< map["color"].value<QColor>();
QStringList sl; //创建一个字符串列表
sl<<"A"<<"B"<<"C"<<"D";
QVariant slv(sl); //将该列表保存在一个QVariant变量中
if(slv.type()==QVariant::StringList)
{
QStringList list=slv.toStringList();
for(int i=0;i<list.size();++i)
qDebug()<<list.at(i); //输出列表内容
}
}
Widget::~Widget()
{
}