W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
今天我們來說說 Qt 容器類中的關(guān)聯(lián)存儲容器。所謂關(guān)聯(lián)存儲容器,就是容器中存儲的一般是二元組,而不是單個的對象。二元組一般表述為,也就是“鍵-值對”。
首先,我們看看數(shù)組的概念。數(shù)組可以看成是一種形式的鍵-值對,它的 Key 只能是int,而值的類型是 Object,也就是任意類型(注意,這里我們只是說數(shù)組可以是任意類型,這個Object 并不必須是一個對象)?,F(xiàn)在我們擴展數(shù)組的概念,把 Key 也做成任意類型的,而不僅僅是int,這樣就是一個關(guān)聯(lián)容器了。如果學(xué)過數(shù)據(jù)結(jié)構(gòu),典型的關(guān)聯(lián)容器就是散列(Hash Map,哈希表)。Qt 提供兩種關(guān)聯(lián)容器類型:QMap<K, T>和 QHash<K, T>。
QMap<K, T>是一種鍵-值對的數(shù)據(jù)結(jié)構(gòu),它實際上使用跳表 skip-list 實現(xiàn),按照 K 進行升序的方式進行存儲。使用 QMap<K, T>的 insert()函數(shù)可以向 QMap<K, T>中插入數(shù)據(jù),典型的代碼如下:
QMap<QString, int> map;
map.insert("eins", 1);
map.insert("sieben", 7);
map.insert("dreiundzwanzig", 23);
同樣,QMap<K, T>也重載了[]運算符,你可以按照數(shù)組的復(fù)制方式進行使用:
map["eins"] = 1;
map["sieben"] = 7;
map["dreiundzwanzig"] = 23;
[]操作符同樣也可以像數(shù)組一樣取值。但是請注意,如果在一個非 const 的 map 中,使用[]操作符取一個不存在的 Key 的值,則這個 Key 會被自動創(chuàng)建,并將其關(guān)聯(lián)的 value 賦予一個空值。如果要避免這種情況,請使用 QMap<K, T>的 value()函數(shù):
int val = map.value("dreiundzwanzig");
如果 key 不存在,基本類型和指針會返回0,對象類型則會調(diào)用默認(rèn)構(gòu)造函數(shù),返回一個對象,與[]操作符不同的是,value()函數(shù)不會創(chuàng)建一個新的鍵-值對。如果你希望讓不存在的鍵返回一個默認(rèn)值,可以傳給 value()函數(shù)第二個參數(shù):
int seconds = map.value("delay", 30);
這行代碼等價于:
int seconds = 30;
if (map.contains("delay"))
seconds = map.value("delay");
QMap<K, T>中的K和T可以是基本數(shù)據(jù)類型,如 int,double,可以是指針,或者是擁有默認(rèn)構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)和賦值運算符的類。并且K必須要重載<運算符,因為 QMap<K, T>需要按 K 升序進行排序。
QMap<K, T>提供了 keys()和 values()函數(shù),可以獲得鍵的集合和值的集合。這兩個集合都是使用QList 作為返回值的。
Map 是單值類型的,也就是說,如果一個新的值分配給一個已存在的鍵,則舊值會被覆蓋。如果你需要讓一個 key 可以索引多個值,可以使用 QMultiMap<K, T>。這個類允許一個 key 索引多個 value,如:
QMultiMap<int, QString> multiMap;
multiMap.insert(1, "one");
multiMap.insert(1, "eins");
multiMap.insert(1, "uno");
QList<QString> vals = multiMap.values(1);
QHash<K, T>是使用散列存儲的鍵-值對。它的接口同 QMap<K, T>幾乎一樣,但是它們兩個的實現(xiàn)需求不同。QHash<K, T>的查找速度比 QMap<K, T>快很多,并且它的存儲是不排序的。對于 QHash<K, T>而言,K 的類型必須重載了==操作符,并且必須被全局函數(shù) qHash()所支持,這個函數(shù)用于返回 key的散列值。Qt 已經(jīng)為 int、指針、QChar、QString 和 QByteArray 實現(xiàn)了 qHash()函數(shù)。
QHash<K, T>會自動地為散列分配一個初始大小,并且在插入數(shù)據(jù)或者刪除數(shù)據(jù)的時候改變散列的大小。我們可以使用 reserve()函數(shù)擴大散列,使用 squeeze()函數(shù)將散列縮小到最小大小(這個最小大小實際上是能夠存儲這些數(shù)據(jù)的最小空間)。在使用時,我們可以使用 reserve()函數(shù)將數(shù)據(jù)項擴大到我們所期望的最大值,然后插入數(shù)據(jù),完成之后使用 squeeze()函數(shù)收縮空間。
QHash<K, T>同樣也是單值類型的,但是你可以使用 insertMulti()函數(shù),或者是使用QMultiHash<K, T>類來為一個鍵插入多個值。另外,除了 QHash<K, T>,Qt 也提供了 QCache<K, T>來提供緩存,QSet用于僅存儲 key 的情況。這兩個類同 QHash<K, T>一樣具有 K 的類型限制。
遍歷關(guān)聯(lián)存儲容器的最簡單的辦法是使用 Java 風(fēng)格的遍歷器。因為 Java 風(fēng)格的遍歷器的 next()和previous()函數(shù)可以返回一個鍵-值對,而不僅僅是值,例如:
QMap<QString, int> map;
...
int sum = 0;
QMapIterator<QString, int> i(map);
while (i.hasNext())
sum += i.next().value();
如果我們并不需要訪問鍵-值對,可以直接忽略 next()和 previous()函數(shù)的返回值,而是調(diào)用 key()和 value()函數(shù)即可,如:
QMapIterator<QString, int> i(map);
while (i.hasNext()) {
i.next();
if (i.value() > largestValue) {
largestKey = i.key();
largestValue = i.value();
}
}
Mutable 遍歷器則可以修改 key 對應(yīng)的值:
QMutableMapIterator<QString, int> i(map);
while (i.hasNext()) {
i.next();
if (i.value() < 0.0)
i.setValue(-i.value());
}
如果是 STL 風(fēng)格的遍歷器,則可以使用它的 key()和 value()函數(shù)。而對于 foreach 循環(huán),我們就需要分別對 key 和 value 進行循環(huán)了:
QMultiMap<QString, int> map;
...
foreach (QString key, map.keys()) {
foreach (int value, map.values(key)) {
doSomething(key, value);
}
}
本文出自 “豆子空間” 博客,請務(wù)必保留此出處 http://devbean.blog.51cto.com/448512/193918
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: