鍍金池/ 教程/ C/ Qt 容器類之關聯存儲容器
Qt 容器和算法拾遺
自定義 model 之一
反走樣
Hello, world!
Qt 容器類之關聯存儲容器
QStringListModel
拖放技術之一
狀態(tài)欄
QTreeWidget
拖放技術之二
通用算法
event()
Qt 學習之路(18): Qt 標準對話框之 QInputDialog
Qt 容器類之遍歷器和隱式數據共享
QListWidget
Meta-Object 系統(tǒng)
事件接收與忽略
Qt 學習之路(tip): parent 參數
Qt 標準對話框之 QColorDialog
QPainter(續(xù))
國際化(下)
漸變填充
自定義委托
創(chuàng)建 shared library
model-view 架構
Graphics View Framework
自定義拖放數據對象
QSortFilterProxyModel
國際化(上)
組件布局
自定義 Model 之三
事件過濾器
QDirModel
Hello, world!(續(xù))
Qt 標準對話框之 QFileDialog
自定義 model 之二
深入了解信號槽
坐標變換
剪貼板操作
QTableWidget
QByteArray 和 QVariant
創(chuàng)建一個對話框(下)
Qt 學習之路(32): 一個簡易畫板的實現(Graphics View)
文本文件讀寫
自定義事件
編寫跨平臺的程序
MainWindow
初探信號槽
Qt 學習之路(17): Qt 標準對話框之 QMessageBox
繪圖設備
菜單和工具條(續(xù))
二進制文件讀寫
QString
事件(event)
菜單和工具條
QPainter
Qt 容器類之順序存儲容器
進程間交互
API 文檔的使用
創(chuàng)建一個對話框(上)
一個簡易畫板的實現(QWidget)

Qt 容器類之關聯存儲容器

今天我們來說說 Qt 容器類中的關聯存儲容器。所謂關聯存儲容器,就是容器中存儲的一般是二元組,而不是單個的對象。二元組一般表述為,也就是“鍵-值對”。

首先,我們看看數組的概念。數組可以看成是一種形式的鍵-值對,它的 Key 只能是int,而值的類型是 Object,也就是任意類型(注意,這里我們只是說數組可以是任意類型,這個Object 并不必須是一個對象)?,F在我們擴展數組的概念,把 Key 也做成任意類型的,而不僅僅是int,這樣就是一個關聯容器了。如果學過數據結構,典型的關聯容器就是散列(Hash Map,哈希表)。Qt 提供兩種關聯容器類型:QMap<K, T>和 QHash<K, T>。

QMap<K, T>是一種鍵-值對的數據結構,它實際上使用跳表 skip-list 實現,按照 K 進行升序的方式進行存儲。使用 QMap<K, T>的 insert()函數可以向 QMap<K, T>中插入數據,典型的代碼如下:


QMap<QString, int> map; 
map.insert("eins", 1); 
map.insert("sieben", 7); 
map.insert("dreiundzwanzig", 23);

同樣,QMap<K, T>也重載了[]運算符,你可以按照數組的復制方式進行使用:


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

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


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

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


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

這行代碼等價于:


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

QMap<K, T>中的K和T可以是基本數據類型,如 int,double,可以是指針,或者是擁有默認構造函數、拷貝構造函數和賦值運算符的類。并且K必須要重載<運算符,因為 QMap<K, T>需要按 K 升序進行排序。

QMap<K, T>提供了 keys()和 values()函數,可以獲得鍵的集合和值的集合。這兩個集合都是使用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>幾乎一樣,但是它們兩個的實現需求不同。QHash<K, T>的查找速度比 QMap<K, T>快很多,并且它的存儲是不排序的。對于 QHash<K, T>而言,K 的類型必須重載了==操作符,并且必須被全局函數 qHash()所支持,這個函數用于返回 key的散列值。Qt 已經為 int、指針、QChar、QString 和 QByteArray 實現了 qHash()函數。

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

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

遍歷關聯存儲容器的最簡單的辦法是使用 Java 風格的遍歷器。因為 Java 風格的遍歷器的 next()和previous()函數可以返回一個鍵-值對,而不僅僅是值,例如:


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

如果我們并不需要訪問鍵-值對,可以直接忽略 next()和 previous()函數的返回值,而是調用 key()和 value()函數即可,如:


QMapIterator<QString, int> i(map); 
while (i.hasNext()) { 
        i.next(); 
        if (i.value() > largestValue) { 
                largestKey = i.key(); 
                largestValue = i.value(); 
        } 
}

Mutable 遍歷器則可以修改 key 對應的值:


QMutableMapIterator<QString, int> i(map); 
while (i.hasNext()) { 
        i.next(); 
        if (i.value() < 0.0) 
                i.setValue(-i.value()); 
}

如果是 STL 風格的遍歷器,則可以使用它的 key()和 value()函數。而對于 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); 
        } 
}

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