IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> QT5开发及实例学习之四容器类 -> 正文阅读

[C++知识库]QT5开发及实例学习之四容器类


前言

??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类

时间复杂度比较

容器类查找插入头部添加尾部添加
QListO(1)O(n)Amort.O(1)Amort.O(1)
QLinkedListO(n)O(1)O(1)O(1)
QVectorO(1)O(n)O(n)Amort.O(1)

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

1.QList类

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

2.QLinkedList类

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

3.QVector类

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

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

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

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

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

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

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

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

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

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

容器类只读迭代器类读写迭代器类
QList<T> , QQueue<T>QList<T>::const_iteratorQList<T>::iterator
QLinkedList<T>QLinkedList<T>::const_iteratorQLinkedList<T>::iterator
QVector<T> , QStack<T>QVector<T>::const_iteratorQVector<T>::iterator

代码如下(示例):

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

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

二、QMap类和QHash类

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

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

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

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

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

1.QMap类

??QMap<Key, T>提供了一个从类型为Key的键到类型为T的值的映射。
??通常,QMap存储的数据形式是一个键对应一个值,且按照键Key的顺序存储数据。为了支持一键多值,QMap提供了QMap<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<Key, T> , QMultiMap<Key, T>QMapIterator<Key, T>QMutableMapIterator<Key, T>
QHash<Key, T> , QMultiHash<Key, T>QHashIterator<Key, T>QMutableHashIterator<Key, T>

代码如下(示例):

#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(); )					//(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<Key, T> , QMultiMap<Key, T>QMap<Key, T>::const_iteratorQMap<Key, T>::iterator
QHash<Key, T> , QMultiHash<Key, T>QHash<Key, T>::const_iteratorQHash<Key, T>::iterator

代码如下(示例):

#include <QCoreApplication>
#include <QDebug>
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<QString, QString>::iterator::value()返回的结果,因为该函数返回的是<键,值>对其中值的引用。

三、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);											//(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::TimeQTime
QVariant::RegionQRegionQVariant::LineQLine
QVariant::BitmapQBitmapQVariant::PaletteQPalette
QVariant::BoolboolQVariant::ListQList
QVariant::BrushQBrushQVariant::SizePolicyQSizePolicy
QVariant::SizeQSizeQVariant::StringQString
QVariant::CharQCharQVariant::MapQMap
QVariant::ColorQColorQVariant::StringListQStringList
QVariant::CursorQCursorQVariant::PointQPoint
QVariant::DateQDateQVariant::PenQPen
QVariant::DateTimeQDateTimeQVariant::PixmapQPixmap
QVariant::DoubledoubleQVariant::RectQRect
QVariant::FontQFontQVariant::ImageQImage
QVariant::IconQIconQVariant::UserType用户自定义类型

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-26 11:56:22  更:2021-08-26 11:58:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 5:22:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计