Qt 容器類之關(guān)聯(lián)存儲容器

2018-10-07 15:17 更新

Qt 容器類之關(guān)聯(lián)存儲容器

今天我們來說說 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

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號