Qt学习02——容器类

一、概述

Qt容器中的数据必须是可赋值的数据类型(即必须提供一个默认的构造函数、一个复制构造函数和一个赋值操作运算符)。这种数据类型包含基本数据类型(int、double等)和Qt的一些数据类型(QString、QTime等)。
注:QObject及其子类(QWidget、QDialog等)不能存储在容器中,因为没有复制构造函数和赋值操作运算符。但是可以用QObject(及其子类)的指针。
例如:
QList<QDialog> list;//错误(但在Qt5.8中未报错)
QList<QDialog*> list;//正确
Qt容器类为遍历提供了2种方法:
1、Java风格的迭代器;
2、STL风格的迭代器,可以与Qt和STL的通用算法一起使用。

二、容器类 QList、QLinkedList、QVector

三种容器类时间复杂度比较(Amort.O(1)表示如果仅完成一次操作可能会有O(n)行为;但完成n>1次操作,平均结果会是O(1)):

1. QList类

QList<T>是最常用的容器类。继承自QList的有QItemSelection、QQueue、QSignalSpy及QStringList和QTestEventList。操作函数有追加列表的QList::append()、QList::prepend()及插入列表的QList::insert()。
QList<T>维护了一个指针数组,指向列表项的内容,提供基于下标的快速访问。
①如果T是一个指针类型或大小和指针相等的基本类型,QList<T>将数值直接存储在数组中。
②如果QList<T>存储对象的指针,则该指针指向实际存储的对象。

用法:
QList<QString> list;
{
    QString str("Hello World.");
    list<<str;
}
qDebug()<<list[0]<<"Hi";
输出:
"Hello World." Hi

2. QLinkedList

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

3. QVector

QVector<T>在相邻的内存中存储给定数据类型T的一组数值。在一个QVector的前部或者中间插入时会导致内存中大量数据被移动,速度很慢。QVector可以使用下标和或迭代器访问。继承自QVector的子类有QPolygon、QPolygonF、QStack。

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

Java风格迭代器损耗轻微性能提升使用的便捷性。对于每一个容器类Qt都有两种Java风格迭代器数据类型:

Java风格迭代点位于第一个列表项的前面,或者两个列表项之间,或者最后一个列表项之后。
例1,QList只读遍历(使用QListIterator()向后遍历):
QList<int> list;
list<<1<<2<<3<<4<<5;
QListIterator<int> i(list);
for(;i.hasNext();)
    qDebug()<<i.next();
}
输出
1
2
3
4
5
例2,QList读写遍历(使用QMutableListIterator()执行读写遍历)
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QList<int> list;//创建容器list
QMutableListIterator<int> i(list);//创建列表list的迭代器
for(int j = 0;j<10;++ j)//插入10个整数
i.insert(j);
for(i.toFront();i.hasNext();)//移动迭代点到表的前端,完成遍历和输出
qDebug()<<i.next();
for(i.toBack();i.hasPrevious();){//移动迭代点到表的后端,遇到偶数则删除,遇到奇数修改为10倍
if(i.previous()%2 == 0)
i.remove();
else
i.setValue(i.peekNext()*10);
}
for(i.toFront();i.hasNext();)
qDebug()<<i.next();
return a.exec();
}

输出


0
1
2
3
4
5
6
7
8
9
10
30
50
70
90


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

对于每一个容器类,Qt都提供两种类型的STL风格迭代器数据类型:

STL风格迭代器的建立在指针操作基础之上。不同于Java风格迭代器,STL风格迭代器迭代点直接指向列表项。
例,
#include <QDebug>
int main(int argc,char *argv[])
{
    QList<int> list;
    for(int j=0;j<10;j++)
        list.insert(list.end(),j);//在列表list之后插入十个整数
    QList<int>::iterator i;
    for(i=list.begin();i!=list.end();++i)//将STL风格列表i所有数值增大10倍
    {
       qDebug()<<(*i);
       *i=(*i)*10;
    }
    QList<int>::const_iterator ci;
    for(ci=list.constBegin();ci!=list.constEnd();++ci)//遍历STL风格列表ci
        qDebug()<<*ci;
    return 0;
}
输出:
0
1
2
3
4
5
6
7
8
9
0
10
20
30
40
50
60
70
80
90

另外,QLinkedList和QVector与QList遍历接口相同,用法一致。


三、容器类QMap、QHash

时间复杂度比较:

区别:
①QHash比QMap查找更快
②QHash以任意顺序存储数据,QMap按Key顺序存储。
③QHash的键类型Key需提供operator==()和一个全局Qhash(Key)函数,二QMap键类型Key必须提供operator<()函数。

1、QMap

QMap<Key,T>提供一个从类型Key到类型T的值得映射。QMap存储数据通常是一个键对应一个值,按Key的次序存储,但为实现一键多值,提供了insertMulti()和values()函数,同时存储多值也可以使用继承自QMap()的QMultiMap<Key,T>。

2、QHash

QHash通过维护的哈希表的大小对应QHash的数据项数目。QHash以任意顺序存储,并可以存储一键多值。也可以通过QMultiHash<Key,T>实现。

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

对于每一个容器类Qt都有两种Java风格迭代器数据类型:

例,
#include <QDebug>
int main(int argc,char *argv[])
{
    QMap<QString,QString> map;
    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();//对i的遍历输出
    QMutableMapIterator<QString,QString> mi(map);//在map中查找"111"并修改
    if(mi.findNext("111"))
        mi.setValue("010");
    QMapIterator<QString,QString> modi(map);
    qDebug()<<"  ";
    for(;modi.hasNext();)
        qDebug()<<" "<<modi.key()<<"  "<<modi.next().value();//再次遍历输出
    return 0;
}
输出:
   "beijing"    "111"
   "nanjing"    "025"
   "shanghai"    "021"
  
  "beijing"    "010"
  "nanjing"    "025"
  "shanghai"    "021"
注意,Java风格迭代器没有提供查找键的函数,因此通过查找值得函数QMutableMapIterator<T,T>实现查找修改。

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

对于每一个容器类,Qt都提供两种类型的STL风格迭代器数据类型:

例,
#include <QDebug>
int main(int argc,char *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();//遍历容器i
    QMap<QString,QString>::iterator mi;
    mi=map.find("beijing");//查找"beijing"
    if(mi!=map.end())
        mi.value()="010";//修改值
    QMap<QString,QString>::const_iterator modi;
    qDebug()<<"  ";
    for(modi=map.constBegin();modi!=map.constEnd();++modi)
        qDebug()<<"  "<<modi.key()<<"  "<<modi.value();//再次遍历
    return 0;
}
注意,这里是通过查找键"beijing"来实现对值"111"的修改。而上面Java风格迭代器是直接修改值。该例输出与Java风格迭代器相同。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章