Qt常用容器類、遍歷方法以及常用函式

語言: CN / TW / HK

Qt容器類

Qt提供了一組通用的基於模板的容器類,相比C++標準模板庫,Qt的容器更輕量安全且更容易使用。同時在速度,記憶體消耗和內聯程式碼等方面進行了優化。

Qt容器可儲存的必須是可賦值的資料型別,也就是說這個型別必須有一個預設的建構函式、複製建構函式和一個賦值操作符。

這樣的資料包含了通常使用的大部分型別,其中包括基本資料型別,和Qt的一些資料型別(比如QString)等,不過,Qt的QObject以及其他的子類(QWidget)等是不能儲存在容器中的,但是可以通過Qt的QObject以及其他的子類的指標。

cpp QList<QToolBar> list; //錯誤 QList<QToolBar* > list; //正確

同時Qt的容器類也是支援巢狀的

cpp QHash<QString,QList<double> > ; //注意最後的> >一定有個空格,否則會被認為是>> 會報錯

Qt容器的兩種遍歷方式:JAVA型和STL型 ,推薦使用STL(通用且效率高)

QList類、QLinkedList類和QVector類

經常使用的容器類有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)|O(1) Amort.O(1)表示如果僅完成一次操作,可能會有O(n)行為,但是如果是多次操作,平均結果將會是O(1)

1.QList類

QList是迄今為止最常用的容器,他的子類有: - QItemSelection

  • QQueue

  • QStringList

  • QTestEventList

Qt提供了可以在列表中追加的QList::append()和QList::prepend()函式,還提供兩個可以插入的函式QList::insert()為了讓可執行程式碼儘可能少,QList被高度優化了。

QList維護了一個指標陣列,該陣列指向QList儲存的列表項的內容,因此QList是支援基於下標的快速訪問的。

對於不同的資料型別,QList會採取不同的儲存策略,分為以下兩種:

cpp 1.如果T是一個指標型別或者指標大小的型別,直接存在容器的陣列中。 2.如果儲存物件的指標,則該指標指向實際儲存的物件。 例如: ------------------------------------- #include<QDebug> int main(){ QList<QString> list; // (a) { QString str("This is a test string"); list << str; // (b) } // (c) qDebug() << list[0] << "How are you!"; return 0; } ------------------------------------- (a)QList<QString> list: 聲明瞭一個QList<QString>棧物件。 (b)list << str 通過運算子將字串存到列表中 (c)程式中使用花括號括起來的作用域表明,此時list儲存的是一個物件的複製。

2.QLinkedList類

QLinkedList是一個鏈式列表,以非連續的記憶體塊儲存資料。

QLinkedList不能使用下標,只能使用迭代器,與QList相比,在對一個很大的列表進行插入操作時,QLinkedList有更高的效率。

3.QVector類

QVector在相鄰的記憶體中儲存給定數型別T的一組數值,在一個QVector的前部或者中間位置進行插入操作速度是很慢的,因為會導致記憶體住的大量資料移動(陣列)。

QVector既可以通過下標訪問,也可以通過迭代器進行訪問,QVector的子類有QPolygon、QPolygonF和QStack。

4.Java風格迭代器遍歷

相比STL風格迭代器遍歷,JAVA更方便,但是效能消耗較大,對於每個容器類,Qt都提供兩種Java風格迭代器資料型別,即只讀訪問和讀寫訪問,可見下表

容 器 類 | 只 讀 迭 代 器 類 | 讀 寫 迭 代 器 類 ---|---|--- QList,QQueue | QListIteator | QMutableListIterator QLinkedList | QLinkedListIteator | QMutableLinkedListIterator QVector | QVectorIteator | QMutableVectorIterator

JAVA風格的迭代點在列表項的中間,而不是直接指向某個列表項,因此,他可能是在第一個列表項的前面,也可能在兩個列表中間,或者是在最後一個列表項之後。

cpp QList<int> list; list << 1 << 2 << 3 << 4 << 5; QListIterator<int> it(list); for(;it.hasNext();) qDebug() << it.next(); 結果為:1 2 3 4 5

上面演示的是向後遍歷,向前遍歷的函式有下面這幾種

QListIterator::toBack(); 將迭代點移動到最後一個列表項的後面

QListIterator::hasPrevious(); 檢查當前迭代點之前是否具有列表項

QListIterator::previous(); 返回前一個列表項的內容並將迭代點移動到前一個列表項之前

除此之外,QListIterator提供的其他函式有下面幾種 cpp toFront(); //移動迭代點到最前面 peekNext(); //返回下一個列表項,但是不移動迭代點 peekPrevious(); //返回前一個列表項,但是不移動迭代點 findNext(); //向後查詢特定列表項,有就true沒有就false,如果沒有,迭代點在列表最後面 findPrevious(); //和findNext類似,如果沒有,迭代點在列表最前面 QListIterator是隻讀迭代器,不能完成插入和刪除操作,需要使用QMutableListIterator,除去QListIterator的函式,他還有insert()插入函式,remove()刪除函式等。

QList<int> list; //空列表 QMutableListIterator<int> it(list); //讀寫迭代器 for(int i = 0; i < 10; i++) { it.insert(i); } for(it.toFront();it.hasNext();) { qDebug() << it.next(); } for(it.toBack();it.hasPrevious();) { if(it.previous() %2 == 0) it.remove(); else it.setValue(it.peekNext() * 10); } for(it.toFront();it.hasNext();) { qDebug() << it.next(); }

STL風格迭代器

容 器 類 | 只 讀 迭 代 器 類 | 讀 寫 迭 代 器 類 ---|---|--- QList,QQueue | QList::const_iterator | QList::iterator QLinkedList | QLinkedList::const_iterator | QLinkedList::iterator QVector | QVector::const_iterator | QVector::iterator STL風格迭代器的API是建立在指標操作基礎上的,比如++可以移動到下一項,而*可以拿到迭代器指向的值。 cpp QList<int> list; for(int j = 0; j < 10; j++) { list.insert(list.end(),j); } QList<int>::iterator i; for(i = list.begin(); i != list.end(); ++i) { qDebug() << (*i); *i = (*i) * 10; } QList<int>::const_iterator ci; for(ci=list.constBegin();ci!=list.constEnd();++ci) { qDebug() << *ci; }

QMap類和QHash類

QMap類和QHash類具有非常類的的功能,他們的差別在於: - QHash具有比QMap更加的查詢速度 - QHash以任意的順序儲存資料項,而QMap總是按照Key的順序儲存資料 - QHash的鍵型別Key必須提供ioeartir==()和一個全域性的qHash(Key)函式,而QMap必須提供operator<()函式。 兩者的複雜度

容 器 類 | 鍵 查 找 |---| 插 入 | --- ---|---|---|---|--- --- | 平均| 最壞| 平均|最壞 QMap |O(log n)|O(log n)|O(log n)|O(log n) QHash |Amort.O(1)|O(n)|Amort.O(1)|O(n)

QMap類

QMap提供了一個型別從Key的鍵到型別為T的值的對映。 通常QMap的資料形式是一個鍵對應一個值,為了支援一鍵多值可以使用QMap::insertMulti()和QMap::values()函式。儲存一鍵多值的資料時,也可以使用QMultiMap 容器,他繼承於QMap。

QHash類

他與QMap的API幾乎完全相同,維持著一張雜湊表,大小與其儲存的資料項的數目相適應。 儲存一鍵多值的資料時,也可以使用QMultiHash 容器,他繼承於QHash。當儲存的資料順序無關緊要時,推薦使用QHash。

Java風格迭代器的兩種分類 容 器 類 | 只 讀 迭 代 器 類 | 讀 寫 迭 代 器 類 ---|---|--- QMap, QMultiMap| QMapIterator | QMutableMapIterator QMultiHash,QHash|QHashIterator | QMutableHashIterator

STL風格迭代器的兩種分類 容 器 類 | 只 讀 迭 代 器 類 | 讀 寫 迭 代 器 類 ---|---|--- QMap, QMultiMap|QMap::const_iterator |QMap::iterator QMultiHash,QHash|QHash::const_iterator | QHash::iterator ```cpp 此處看一看STL的呼叫,JAVA參考上面List QMap map; map.insert("111","aaa"); map.insert("222","bbb"); map.insert("333","ccc");

QMap<QString,QString>::const_iterator cit;
for(cit = map.constBegin();cit != map.constEnd();++cit)
{
    qDebug() << " " << cit.key() << " " << cit.value();
}
QMap<QString,QString>::iterator it;
it=map.find("111");
if(it != map.end())
{
    it.value() = "ddd";
}
QMap<QString,QString>::const_iterator ccit;
for(ccit = map.constBegin();ccit != map.constEnd();++ccit)
{
    qDebug() << " " << ccit.key() << " " << ccit.value();
}

```