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風格迭代器相同。


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