QT5开发及实例学习之四容器类

文章目录

  • 前言
  • 一、QList类、QLinkedList类和QVector类
    • 1.QList类
    • 2.QLinkedList类
    • 3.QVector类
    • 4.Java风格迭代器遍历容器
    • 5.STL风格迭代器遍历容器
  • 二、QMap类和QHash类
    • 1.QMap类
    • 2.QHash类
    • 3.Java风格迭代器遍历容器
    • 4.STL风格迭代器遍历容器
  • 三、QVariant类


前言

  Qt提供了一组通用的基于模板的容器类。
  优点:相比C++的标准模板库中的容器类,Qt的容器更轻量、更安全且更容易使用。Qt的容器类在速度、内存消耗和内联(inline)代码等方面进行了优化。
  Qt容器类中存储的数据必须是可赋值的数据类型,也就是说:这种数据类型必须提供一个默认的构造函数(不需要参数的构造函数)、一个复制构造函数和一个赋值操作运算符。
  这样的数据类型包括基本数据类型(int和double等)和Qt的一些数据类型(QString、QDate和QTime等);也可存储QObject及其子类的指针,例如:

QList<QToolBar*> list;

Qt的容器类是可以嵌套的,例如:

QHash< QString, QList<double> >

  Qt的容器类为遍历其中内容,提供两种方法:
(1)Java风格的迭代器
(2)STL风格的迭代器;能同Qt和STL的通用算法一起用,效率更高。


一、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)

其中,"Amort.O(1)"表示,若仅完成一次操作,可能会有O(n)行为;若完成多次操作,平均结果将是O(1)。

1.QList类

  QList是最常用的容器类,它存储给定数据类型T的一列数值。继承自QList类的子类有QItemSelection、QQueue、QSignalSpy、QStringList和QTestEventList。
  QList类提供了在列表中追加的函数(QList::append()和QList::prepend());在列表中间完成插入操作的函数(QList::insert())。
  QList维护了一个指针数组,该数组存储的指针指向QList存储的列表项的内容;QList提供基于下标的快速访问。
  存储策略有以下几种:
 (1)若T是指针类型或指针大小的基本类型(即该基本类型占有的字节数和指针类型占有的字节数相同),QList会将数值直接存储在数组中。
 (2)若QList存储对象的指针,则该指针指向实际存储的对象。

2.QLinkedList类

  QLinkedList是一个链式列表,它以非连续的内存块保存数据。
  QLinkedList不能使用下标,只能使用迭代器访问它的数据项。
  对一个很大的列表进行插入操作时,QLinkedList比QList效率更高。

3.QVector类

  QVector在相邻的内存中存储给定数据类型T的一组数值。
  QVector既可以使用下标访问数据项,也可以使用迭代器访问数据项;继承的子类有QPolygon、QPolygonF和QStack。
  缺点:在QVector的前部或中间位置进行插入操作的速度是很慢的,因为此操作会导致内存中大量数据被移动。

4.Java风格迭代器遍历容器

  Qt提供了两种类型的Java风格迭代器数据类型,即只读迭代器类和读写迭代器类,如下表:

容器类 只读迭代器类 读写迭代器类
QList , QQueue QListIterator QMutableListIterator
QLinkedList QLinkedListIterator QMutableLinkedListIterator
QVector , QStack QVectorIterator QMutableVectorIterator

  Java风格迭代器的迭代点位于列表项的中间,而不是直接指向某个列表项。因此,它的迭代点或者在第一个列表项的前面,或者在两个列表项之间,或者在最后一个列表项之后。
  以QList为例,介绍两种Java风格迭代器的用法:
(1)QList只读遍历方法。
代码如下(示例):

#include 
#include 						//(a)
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);		//(b)
	QList<int> list;					//创建一个QList栈对象list
	list<<1<<2<<3<<4<<5;				//用操作运算符"<<"输入五个整数
	QListIterator<int> i(list);			//(c)
	for(; i.hasNext(); )				//(d)
		qDebug()<<i.next();
	return a.exec();
}

 (a)头文件中已经包含了QList的头文件
 (b)Qt的一些类,如QString、QList等,不需要QCoreApplication的支持也能工作,但在使用Qt编写应用程序时,如果是控制台应用程序,则建议初始化一个QCoreApplication对象;如果是GUI图形用户界面程序,则会初始化一个QApplication对象
 (c)QListIterator i(list):以该list为参数初始化一个QListIterator对象i;此时迭代点处在第一个列表项"1"的前面(注意:并不是指向该列表项)
 (d)for(; i.hasNext(); ):调用QListIterator::hasNext()函数检查当前迭代点之后是否有列表项;如果有则调用QListIterator::next()函数进行遍历。next()函数会跳过下一个列表项(即迭代点将会位于第一个列表项和第二个列表项之间),并返回它跳过的列表项的内容。
 对列表项向前遍历的函数:
  QListIterator::toBack():将迭代点移动到最后一个列表项的后面。
  QListIterator::hasPrevious():检查当前迭代点之前是否具有列表项。
  QListIterator::previous():返回前一个列表项的内容并将迭代点移动到前一个列表项之前。
 其他函数:
  toFront():移动迭代点到列表的前端(第一个列表项的前面)。
  peekNext():返回下一个列表项,但不移动迭代点。
  peekPrevious():返回前一个列表项,但不移动迭代点。
  findNext():从当前迭代点开始向后查找指定的列表项,找到返回true,此时迭代点位于匹配列表项的后面;未找到返回false,此时迭代点位于列表的后端(最后一个列表项的后面)。
  findPrevious():与findNext()类似,但它的方向是向前的,查找完成后迭代点在匹配想的前面或整个列表的前端。
(2)读写迭代器QMutableListIterator除提供基本的遍历操作(与QListIterator的操作相同)外,还提供了insert()插入操作函数、remove()删除操作函数和修改数据函数等。
代码如下(示例):

#include 
#include 
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	QList<int> list;					//创建一个空的列表list
	QMutableListIterator<int> i(list);	//创建上述列表的读写迭代器
	for(int j = 0; j < 10; ++j)
		i.insert(j);					//(a)
	for(i.toFront(); i.hasNext(); )		//(b)
		qDebug() << i.next();
	for(i.toBack(); i.hasPrevious(); )	//(c)
	{
		if(i.previous()%2 == 0)
			i.remove();
		else
			i.setValue(i.peekNext()*10);//(d)
	}
	for(i.toFront(); i.hasNext(); )		//重新遍历并输出列表
		qDebug() << i.next();
	return a.exec();
}

 (a)i.insert(j):通过QMutableListIterator::insert()插入操作,为该列表插入10个整数值。
 (b)将迭代器的迭代点移动到列表的前端,完成对列表的遍历和输出。
 (c)移动迭代器的迭代点到列表的后端,对列表进行遍历。如果前一个列表项的值为偶数,则将该列表项删除;否则,将该列表项的值修改为原来的10倍。
 (d)函数QMutableListIterator::setValue()修改遍历函数next()、previous()、findNext()、findPrevious()跳过的列表项的值,但不会移动迭代点的位置。对于findNext()和findPrevious():当findNext()(或findPrevious())查找到列表项的时候,setValue()将会修改匹配的列表项;若未找到,则对setValue()的调用将不会进行任何修改。

5.STL风格迭代器遍历容器

  对于每个容器类,Qt都提供了两种类型的STL风格迭代器数据类型:一种提供只读访问;一种提供读写访问。
  STL风格迭代器的API是建立在指针操作基础上的。如,"++“操作运算符移动迭代器到下一项(item),而”*"操作运算符返回迭代器指向的项。
  STL风格迭代器的迭代点直接指向列表项。
STL风格迭代器的两种分类:

容器类 只读迭代器类 读写迭代器类
QList , QQueue QList::const_iterator QList::iterator
QLinkedList QLinkedList::const_iterator QLinkedList::iterator
QVector , QStack QVector::const_iterator QVector::iterator

代码如下(示例):

#include 
#include 
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	QList<int> list;							//初始化一个空的QList列表
	for(int j = 0; j < 10; j++)
		list.insert(list.end(), j);				//(a)
	QList<int>::iterator i;						//初始化一个QList::iterator读写迭代器
	for(i = list.begin(); i != list.end(); ++i)	//(b)
	{
		qDebug() << (*i);
		*i = (*i) * 10;
	}
	QList<int>::const_iterator ci;				//初始化一个QList::const_iterator读写迭代器
	for(ci = list.constBegin(); ci != list.constEnd(); ++ci)
		qDebug() << *ci;						//在控制台输出列表的所有值
	return a.exec();
}

 (a)使用QList::insert()函数插入10个整数值。函数两个参数:第一个参数是QList::iterator类型,表示在该列表项之前插入一个新的列表项(使用QList::end()函数返回的迭代器,表示在列表的最后插入一个列表项);第二个参数指定了需要插入的值。
 (b)在控制台输出列表的同时将列表的所有值增大10倍。QList::begin()函数返回指向第一个列表项的迭代器;QList::end()函数返回一个容器最后列表项之后的虚拟列表项,为标记无效位置的迭代器,用于判断是否到达容器的底部。
  QLinkedList和QVector具有和QList相同的遍历接口。

二、QMap类和QHash类

  QMap类和QHash类具有类似的功能,差别仅在于:

  • QHash具有比QMap更快的查找速度;
  • QHash以任意顺序存储数据项,而QMap按照键Key的顺序存储数据;
  • QHash的键类型Key必须提供operator==()和一个全局的qHash(Key)函数,而QMap的键类型Key必须提供operator<()函数。

QMap和QHash的时间复杂度比较:

容器类 键查找 键查找 插入 插入
容器类 平均 最坏 平均 最坏
QMap O(log n) O(log n) O(log n) O(log n)
QHash Amort.O(1) O(n) Amort.O(1) O(n)

  其中,"Amort.O(1)"表示,若仅完成一次操作,则可能会有O(n)行为;若完成多次操作(如n次),则平均结果将是O(1)。

1.QMap类

  QMap提供了一个从类型为Key的键到类型为T的值的映射。
  通常,QMap存储的数据形式是一个键对应一个值,且按照键Key的顺序存储数据。为了支持一键多值,QMap提供了QMap::insertMulti()和QMap::values()函数。存储一键多值的数据时,也可以使用QMultiMap容器,继承自QMap。

2.QHash类

  QHash具有与QMap几乎相同的API。QHash维护着一张哈希表(Hash Table),哈希表的大小与QHash的数据项的数目相适应。
  QHash以任意顺序组织数据。当存储数据的顺序无关紧要时,建议使用QHash作为存放数据的容器。
  QHash也可以存储一键多值形式的数据,子类QMultiHash可实现。

3.Java风格迭代器遍历容器

Java风格迭代器的两种分类:

容器类 只读迭代器类 读写迭代器类
QMap , QMultiMap QMapIterator QMutableMapIterator
QHash , QMultiHash QHashIterator QMutableHashIterator

代码如下(示例):

#include 
#include 
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(); )					//(a)
	{
		i.next();
		qDebug() << " " << i.key() << " " << i.value();
	}
	QMutableMapIterator<QString, QString> mi(map);
	if(mi.findNext("111"))					//(b)
		mi.setValue("010");
	QMapIterator<QString, QString> modi(map);
	qDebug() << " ";
	for( ; modi.hasNext(); )				//再次遍历并输出修改后的结果
	{
		modi.next();
		qDebug() << " " << modi.key() << " " << modi.value();
	}
	return a.exec();
}

(a)完成对QMap的遍历输出。在输出QMap的键和值时,调用的函数是不同的,在调用函数前必须先将迭代点移动到下一位置。
(b)首先查找<键,值>对,然后修改值。Java风格的迭代器未提供查找键的函数。

4.STL风格迭代器遍历容器

STL风格迭代器的两种分类:

容器类 只读迭代器类 读写迭代器类
QMap , QMultiMap QMap::const_iterator QMap::iterator
QHash , QMultiHash QHash::const_iterator QHash::iterator

代码如下(示例):

#include 
#include 
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	QMap<QString, QString> map;
	map.insert("beijing", "111");
	map.insert("shanghai", "021");
	map.insert("nanjing", "025");
	QMap<QString, QString>::const_iterator i;
	for(i = map.constBegin(); i != map.constEnd(); ++i)
		qDebug() << " " << i.key() << " " << i.value();
	QMap<QString, QString>::iterator mi;
	mi = map.find("beijing");
	if(mi != map.end())
		mi.value() = "010";							//(a)
	QMap<QString, QString>::const_iterator modi;
	qDebug() << " ";
	for(modi = map.constBegin(); modi != map.constend(); ++modi)
		qDebug() << " " << modi.key() << " " << modi.value();
	return a.exec();
}

(a)将新的值直接赋给QMap::iterator::value()返回的结果,因为该函数返回的是<键,值>对其中值的引用。

三、QVariant类

  QVariant类类似于C++的联合(union)数据类型,不仅能保存Qt类型的值,包括QColor、QBrush、QFont、QPen、QRect、QString、QSize等;也能存放Qt的容器类型的值。Qt的很多功能都建立在QVariant基础上,如Qt的对象属性及数据库功能等。
代码如下(示例):

#include "widget.h"
#include 
#include 
#include 

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QVariant v(709);											//(a)
    qDebug() << v.toInt();										//(b)

    QVariant w("How are you! ");								//(c)
    qDebug() << w.toString();									//(d)

    QMap<QString, QVariant>map;									//(e)
    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>();	//(f)

    QStringList sl;												//创建一个字符串列表
    sl << "A" << "B" << "C" << "D";
    QVariant slv(sl);											//将该列表保存在一个QVariant变量中
    if(slv.type() == QVariant::StringList)						//(g)
    {
        QStringList list = slv.toStringList();
        for(int i = 0; i < list.size(); ++i)
            qDebug() << list.at(i);								//输出列表内容
    }
}

Widget::~Widget()
{

}

(a)声明一个QVariant变量v,并初始化一个整数。
(b)调用QVariant::toInt()函数将QVariant变量包含的内容转换为整数并输出。
(c)声明一个QVariant变量w,并初始化为一个字符串。
(d)调用QVariant::toString()函数将QVariant变量包含的内容转换为字符串并输出。
(e)声明一个QMap变量map,使用字符串作为键,QVariant变量作为值。
(f)在QVariant变量中保存了一个QColor对象,并使用模板QVariant::value()还原为QColor,然后输出。由于QVariant是QCore模块的类,所以没有数据类型提供转换,因此需要QVariant::value()函数或QVariantValue()模块函数。
(g)QVariant::type()函数返回存储在QVariant变量中的值的数据类型。

Qt常用的QVariant::type枚举类型变量:

变量 对应的类型 变量 对应的类型
QVariant::Invalid 无效类型 QVariant::Time QTime
QVariant::Region QRegion QVariant::Line QLine
QVariant::Bitmap QBitmap QVariant::Palette QPalette
QVariant::Bool bool QVariant::List QList
QVariant::Brush QBrush QVariant::SizePolicy QSizePolicy
QVariant::Size QSize QVariant::String QString
QVariant::Char QChar QVariant::Map QMap
QVariant::Color QColor QVariant::StringList QStringList
QVariant::Cursor QCursor QVariant::Point QPoint
QVariant::Date QDate QVariant::Pen QPen
QVariant::DateTime QDateTime QVariant::Pixmap QPixmap
QVariant::Double double QVariant::Rect QRect
QVariant::Font QFont QVariant::Image QImage
QVariant::Icon QIcon QVariant::UserType 用户自定义类型

你可能感兴趣的:(QT5开发及实例学习笔记,qt,c++)