Qt學習之路(37): Qt容器類之關聯存儲容器

原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章 原始出處 、作者信息和本聲明。否則將追究法律責任。http://devbean.blog.51cto.com/448512/248373

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

 

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

 

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

 

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

 

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

 

InBlock.gifmap["eins"] = 1; 
InBlock.gifmap["sieben"] = 7; 
InBlock.gifmap["dreiundzwanzig"] = 23;

 

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

 

InBlock.gifint val = map.value("dreiundzwanzig");

 

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

 

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

 

這行代碼等價於:

 

InBlock.gifint seconds = 30; 
InBlock.gifif (map.contains("delay")) 
InBlock.gif        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,如:

 

InBlock.gifQMultiMap<int, QString> multiMap; 
InBlock.gifmultiMap.insert(1, "one"); 
InBlock.gifmultiMap.insert(1, "eins"); 
InBlock.gifmultiMap.insert(1, "uno"); 
InBlock.gif 
InBlock.gifQList<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<K>用於僅存儲key的情況。這兩個類同QHash<K, T>一樣具有K的類型限制。

 

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

 

InBlock.gifQMap<QString, int> map; 
InBlock.gif... 
InBlock.gifint sum = 0; 
InBlock.gifQMapIterator<QString, int> i(map); 
InBlock.gifwhile (i.hasNext()) 
InBlock.gif        sum += i.next().value();

 

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

 

InBlock.gifQMapIterator<QString, int> i(map); 
InBlock.gifwhile (i.hasNext()) { 
InBlock.gif        i.next(); 
InBlock.gif        if (i.value() > largestValue) { 
InBlock.gif                largestKey = i.key(); 
InBlock.gif                largestValue = i.value(); 
InBlock.gif        } 
InBlock.gif}

 

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

 

InBlock.gifQMutableMapIterator<QString, int> i(map); 
InBlock.gifwhile (i.hasNext()) { 
InBlock.gif        i.next(); 
InBlock.gif        if (i.value() < 0.0) 
InBlock.gif                i.setValue(-i.value()); 
InBlock.gif}

 

如果是STL風格的遍歷器,則可以使用它的key()和value()函數。而對於foreach循環,我們就需要分別對key和value進行循環了:

 

InBlock.gifQMultiMap<QString, int> map; 
InBlock.gif... 
InBlock.gifforeach (QString key, map.keys()) { 
InBlock.gif        foreach (int value, map.values(key)) { 
InBlock.gif                doSomething(key, value); 
InBlock.gif        } 
InBlock.gif

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章