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

2018-10-07 15:17 更新

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

今天我們來說說 Qt 容器類中的關(guān)聯(lián)存儲(chǔ)容器。所謂關(guān)聯(lián)存儲(chǔ)容器,就是容器中存儲(chǔ)的一般是二元組,而不是單個(gè)的對(duì)象。二元組一般表述為,也就是“鍵-值對(duì)”。

首先,我們看看數(shù)組的概念。數(shù)組可以看成是一種形式的鍵-值對(duì),它的 Key 只能是int,而值的類型是 Object,也就是任意類型(注意,這里我們只是說數(shù)組可以是任意類型,這個(gè)Object 并不必須是一個(gè)對(duì)象)。現(xiàn)在我們擴(kuò)展數(shù)組的概念,把 Key 也做成任意類型的,而不僅僅是int,這樣就是一個(gè)關(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>是一種鍵-值對(duì)的數(shù)據(jù)結(jié)構(gòu),它實(shí)際上使用跳表 skip-list 實(shí)現(xiàn),按照 K 進(jìn)行升序的方式進(jìn)行存儲(chǔ)。使用 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>也重載了[]運(yùn)算符,你可以按照數(shù)組的復(fù)制方式進(jìn)行使用:


map["eins"] = 1; 
map["sieben"] = 7; 
map["dreiundzwanzig"] = 23;

[]操作符同樣也可以像數(shù)組一樣取值。但是請(qǐng)注意,如果在一個(gè)非 const 的 map 中,使用[]操作符取一個(gè)不存在的 Key 的值,則這個(gè) Key 會(huì)被自動(dòng)創(chuàng)建,并將其關(guān)聯(lián)的 value 賦予一個(gè)空值。如果要避免這種情況,請(qǐng)使用 QMap<K, T>的 value()函數(shù):


int val = map.value("dreiundzwanzig");

如果 key 不存在,基本類型和指針會(huì)返回0,對(duì)象類型則會(huì)調(diào)用默認(rèn)構(gòu)造函數(shù),返回一個(gè)對(duì)象,與[]操作符不同的是,value()函數(shù)不會(huì)創(chuàng)建一個(gè)新的鍵-值對(duì)。如果你希望讓不存在的鍵返回一個(gè)默認(rèn)值,可以傳給 value()函數(shù)第二個(gè)參數(shù):


int seconds = map.value("delay", 30);

這行代碼等價(jià)于:


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ù)和賦值運(yùn)算符的類。并且K必須要重載<運(yùn)算符,因?yàn)?QMap<K, T>需要按 K 升序進(jìn)行排序。

QMap<K, T>提供了 keys()和 values()函數(shù),可以獲得鍵的集合和值的集合。這兩個(gè)集合都是使用QList 作為返回值的。

Map 是單值類型的,也就是說,如果一個(gè)新的值分配給一個(gè)已存在的鍵,則舊值會(huì)被覆蓋。如果你需要讓一個(gè) key 可以索引多個(gè)值,可以使用 QMultiMap<K, T>。這個(gè)類允許一個(gè) key 索引多個(gè) 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>是使用散列存儲(chǔ)的鍵-值對(duì)。它的接口同 QMap<K, T>幾乎一樣,但是它們兩個(gè)的實(shí)現(xiàn)需求不同。QHash<K, T>的查找速度比 QMap<K, T>快很多,并且它的存儲(chǔ)是不排序的。對(duì)于 QHash<K, T>而言,K 的類型必須重載了==操作符,并且必須被全局函數(shù) qHash()所支持,這個(gè)函數(shù)用于返回 key的散列值。Qt 已經(jīng)為 int、指針、QChar、QString 和 QByteArray 實(shí)現(xiàn)了 qHash()函數(shù)。

QHash<K, T>會(huì)自動(dòng)地為散列分配一個(gè)初始大小,并且在插入數(shù)據(jù)或者刪除數(shù)據(jù)的時(shí)候改變散列的大小。我們可以使用 reserve()函數(shù)擴(kuò)大散列,使用 squeeze()函數(shù)將散列縮小到最小大小(這個(gè)最小大小實(shí)際上是能夠存儲(chǔ)這些數(shù)據(jù)的最小空間)。在使用時(shí),我們可以使用 reserve()函數(shù)將數(shù)據(jù)項(xiàng)擴(kuò)大到我們所期望的最大值,然后插入數(shù)據(jù),完成之后使用 squeeze()函數(shù)收縮空間。

QHash<K, T>同樣也是單值類型的,但是你可以使用 insertMulti()函數(shù),或者是使用QMultiHash<K, T>類來為一個(gè)鍵插入多個(gè)值。另外,除了 QHash<K, T>,Qt 也提供了 QCache<K, T>來提供緩存,QSet用于僅存儲(chǔ) key 的情況。這兩個(gè)類同 QHash<K, T>一樣具有 K 的類型限制。

遍歷關(guān)聯(lián)存儲(chǔ)容器的最簡單的辦法是使用 Java 風(fēng)格的遍歷器。因?yàn)?Java 風(fēng)格的遍歷器的 next()和previous()函數(shù)可以返回一個(gè)鍵-值對(duì),而不僅僅是值,例如:


QMap<QString, int> map; 
... 
int sum = 0; 
QMapIterator<QString, int> i(map); 
while (i.hasNext()) 
        sum += i.next().value();

如果我們并不需要訪問鍵-值對(duì),可以直接忽略 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 對(duì)應(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ù)。而對(duì)于 foreach 循環(huán),我們就需要分別對(duì) key 和 value 進(jìn)行循環(huán)了:


QMultiMap<QString, int> map; 
... 
foreach (QString key, map.keys()) { 
        foreach (int value, map.values(key)) { 
                doSomething(key, value); 
        } 
}

本文出自 “豆子空間” 博客,請(qǐng)務(wù)必保留此出處 http://devbean.blog.51cto.com/448512/193918

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)