一、介紹
Qt庫提供了一套通用的基於模板的容器類,可以用這些類存儲指定類型的項。比如,你需要一個大小可變的QString的數組,則使用QVector<QString>。
這些容器類比STL(C++標准模板庫)容器設計得更輕量、更安全並且更易於使用。如果對STL不熟悉,或者傾向於用“Qt的方式”,那么你可以使用這些類,而不去使用STL的類。
你可以用兩種方式遍歷容器內存儲的項:Java風格的迭代器和STL風格的迭代器。Java風格的迭代器更易於使用,並且提供了更高級的功能;STL風格的迭代器更高效,並且可以和Qt與STL的泛型算法一起使用。
Qt還提供了foreach關鍵字使我們方便地遍歷容器中的項。
二、容器類
Qt提供了一些順序容器:QList、QLinkedList、QVector、QStack和QQueue。因為這些容器中的數據都是一個接一個線性存儲的,所以稱為順序容器。大多數時候,QList是最好的選擇,雖然是用數組實現的,但在它的首尾添加元素都非常快。如果你需要一個鏈表(linked-list)就用QLinkedList;想要你的項在內存中連續存儲,就使用QVector。QStack和QQueue(棧和隊列)分別提供了后進先出(LIFO)和先進先出(FIFO)的機制。
Qt還提供了一些關聯容器:QMap、QMultiMap、QHash、QMultiHash、QSet。因為這些容器存儲的是<鍵,值>對,比如QMap<Key,T>,所以稱為關聯容器。其中“Multi”容器支持一個鍵對應多個值。“Hash”容器在有序集合上使用hash函數進行快速的查找,而沒有用二叉搜索。
下表對常用的容器類進行了介紹。
類 | 概述 |
---|---|
QList<T> | 這是目前使用最頻繁的容器類,它存儲了指定類型(T)的一串值,可以通過索引來獲得。本質上QList是用數組實現的,從而保證基於索引的訪問非常快。 |
QLinkedList<T> | 類似於QList,但它使用迭代器而不是整數索引來獲得項。當在一個很大的list中間插入項時,它提供了更好的性能,並且它有更好的迭代器機制。 |
QVector<T> | 在內存中相鄰的位置存儲一組值,在開頭或中間插入會非常慢,因為它會導致內存中很多項移動一個位置。 |
QStack<T> | QVector的一個子類,提供后進先出的機制。在當前的QVector中增加了幾個方法:push()、pos()、top()。 |
QQueue<T> | QList的一個子類,提供了先進先出的機制,在當前的QList中增加了幾個方法:enqueue()、dequeue()、head()。 |
QSet<T> | 單值的數學集合,能夠快速查找。 |
QMap<Key, T> | 提供了字典(關聯數組)將類型Key的鍵對應類型T的值。通常一個鍵對應一個值,QMap以Key的順序存儲數據,如果順序不重要,QHash是一個更快的選擇。 |
QMultiMap<Key, T> | QMap的子類,提供了多值的接口,一個鍵對應多個值。 |
QHash<Key, T> | 和QMap幾乎有着相同的接口,但查找起來更快。QHash存儲數據沒有什么順序。 |
QMultiHash<Key, T> | QHash的子類,提供了多值的接口。 |
容器也可以嵌套使用,例如QMap<QString,QList<int> >,這里鍵的類型是QString,而值的類型是QList<int>,需要注意,在后面的“> >”符號之間要有一個 空格,不然編譯器會將它當作“>>”操作符對待。
在各種容器中存儲的值類型可以是任何的可賦值的數據類型,像基本的類型double、指針類型、Qt的數據類型(如QString、 QDate、QTime)等。但是QObject以及QObject的子類都不能存儲在容器中,不過,可以存儲這些類的指針,例如QList<QWidget * >。
三、QList和QMap的示例程序
下面分別對最為常用的QList和QMap進行介紹,而對於其他幾個容器,可以參照着進行操作,因為它們的接口函數是很相似的,當然也可以參考幫助手冊。
QList的示例程序
新建Qt
5控制台應用,項目名稱為
myQList。這里只是為了演示QList容器類的使用,所以沒有使用圖形界面,這樣只需要建立控制台程序就可以了。將main.cpp文件更改如下:
#include <QCoreApplication>
#include <QList>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//創建QList列表
QList<QString> list;
//插入項目
list << "aa" << "bb";
//在列表尾部添加
list.append("cc");
//在列表頭部添加
list.prepend("mm");
//將第一個項目值換為“bc”
list.replace(0, "ss");
//第一次遍歷輸出列表項目值
qDebug() << "the no.1 list is: ";
for(int i=0; i<list.size(); ++i)
{
qDebug() << list.at(i); //現在列表為ss aa bb cc
}
qDebug() << endl;
//----------------------------------------------------------
QString str = list.takeAt(1); //從列表中刪除位置1的項目,並獲取它
qDebug() << "at(1) item is: " << str;
//在位置1插入項目
list.insert(1, "ab");
//交換項目1和項目2
list.swap(1,2);
//第二次遍歷輸出列表項目值
qDebug() << "the no.2 list is: ";
for(int i=0; i<list.size(); ++i)
{
qDebug() << list.at(i); //現在列表為ss bb ab cc
}
qDebug() << endl;
//-----------------------------------------------------------
//查詢列表中是否包含“ss”
qDebug() << "contains 'ss' ?" << list.contains("ss");
//查詢列表中包含“mm”的個數
qDebug() << "the 'ss' count: " << list.count("ss");
// 第一個“ss”的位置,默認從位置0開始往前查找,返回第一個匹配的項目的位置
qDebug() << "the first 'ss' index: " << list.indexOf("ss");
// 第二個“ss”的位置,我們指定從位置1開始往前查找,未找到則返回-1
qDebug() << "the second 'ss' index: " << list.indexOf("ss", 1);
return a.exec();
}
運行程序,Qt的“應用程序輸出”窗口輸出如下:
the no.1 list is:
"ss"
"aa"
"bb"
"cc"
at(1) item is: "aa"
the no.2 list is:
"ss"
"bb"
"ab"
"cc"
contains 'ss' ? true
the 'ss' count: 1
the first 'ss' index: 0
the second 'ss' index: -1
QList是一個模板類,提供了一個列表。QList<T>實際上是一個T類型項目的指針數組,所以支持基於索引的訪問,而且當項目的數目小於1000時,可以實現在列表中間進行快速的插入操作。
QList提供了很多方便的接口函數來操作列表中的項目,例如插入操作insert()、替換操作replace()、移除操作removeAt()、移動操作move()、交換操作swap()、在表尾添加項目append()、在表頭添加項目prepend()、從列表中移除一項並獲取這個項目takeAt()及相應的takeFirst()和takeLast()、獲取一個項目的索引indexOf()、判斷是否含有相應的項目contains()以及獲取一個項目出現的次數count()等。
對於QList,可以使用“<<’’操作符來向列表中插入項目,也可以使用“[]”操作符通過索引來訪問一個項目,其中項目是從0開始編號的。不過,對於只讀的訪問,另一種方法是使用at()函數,比操作符要快很多。
QMap的示例程序
新建Qt
5控制台應用,項目名稱為
myMap。這里只是為了演示QMap容器類的使用,所以沒有使用圖形界面,這樣只需要建立控制台程序就可以了。將main.cpp文件更改如下:
#include <QCoreApplication>
#include <QMap>
#include <QMultiMap>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//創建QMap
QMap<QString, int> map;
map["one"] = 1; //向map中插入("one",1)
map["three"] = 3;
//使用insert()函數進行插入
map.insert("seven", 7);
//獲取鍵的值,使用“[ ]”操作符時如果map中沒有該鍵,那么會自動插入
int value1 = map["six"]; //如果map中沒有該鍵,則返回0
qDebug() << "value1:" << value1;
qDebug() << "contains 'six' ?" << map.contains("six") << endl;
//使用value()函數獲取鍵的值,這樣當鍵不存在時不會自動插入
int value2 = map.value("five");
qDebug() << "value2:" << value2;
qDebug() << "contains 'five' ?" << map.contains("five") << endl;
//當鍵不存在時,value()默認返回0,這里可以設定該值,比如這里設置為9
int value3 = map.value("nine", 9);
qDebug() << "value3:" << value3 << endl;
//map默認是一個鍵對應一個值,如果重新給該鍵設置了值,那么以前的會被擦除
map.insert("ten", 10);
map.insert("ten", 100);
qDebug() << "ten: " << map.value("ten") << endl;
//可以使用insertMulti()函數來實現一鍵多值,然后使用values()函數來獲取值的列表
map.insertMulti("two", 2);
map.insertMulti("two", 4);
QList<int> values = map.values("two");
qDebug() << "two: " << values << endl;
//------------------------------------------------------------------
//也可以使用QMultiMap類來實現一鍵多值
QMultiMap<QString, int> map1, map2, map3;
map1.insert("values", 1);
map1.insert("values", 2);
map2.insert("values", 3);
//可以進行相加,這樣map3的“values”鍵將包含2,1,3三個值
map3 = map2 + map1;
QList<int> myValues = map3.values("values");
qDebug() << "the values are: ";
for (int i=0; i<myValues.size(); ++i)
{
qDebug() << myValues.at(i);
}
return a.exec();
}
運行程序,Qt的“應用程序輸出”窗口輸出如下:
value1: 0
contains 'six' ? true
value2: 0
contains 'five' ? false
value3: 9
ten: 100
two: (4, 2)
the values are:
2
1
3
QMap類是一個容器類,提供了一個基於跳躍列表的字典(a skip-list-based dictionary)。QMap<Key,T>是Qt的通用容器類之一,它存儲(鍵,值)對並提供了與鍵相關的值的快速查找。
QMap中提供了很多方便的接口函數,例如插人操作inSert()、獲取值value()、是否包含一個鍵contains()、刪除一個鍵remove()、刪除一個鍵並獲取該鍵對應的值take()、插入一鍵多值insertMulti()等。
可以使用 “[]”操作符插入一個鍵值對或者獲取一個鍵的值,不過當使用該操作符獲取一個不存在的鍵的值時,會默認向map中插人該鍵;為了避免這個情況,可以使用value()函數來獲取鍵的值。當使用value()函數時,如果指定的鍵不存在,那么默認會返回0,可以在使用該函數時提供參數來更改這個默認返回的值。QMap默認是一個鍵對應一個值的,但是也可以使用insertMulti()進行一鍵多值的插入,對於一鍵多值的情況,更方便的是使用QMap的子類QMultiMap。
參考: