當我們談論程式設計中的資料結構時,順序容器是不可忽視的一個重要概念。順序容器是一種能夠按照元素新增的順序來儲存和檢索資料的資料結構。它們提供了簡單而直觀的方式來組織和管理資料,為程式設計師提供了靈活性和效能的平衡。
Qt 中提供了豐富的容器類,用於方便地管理和運算元據。這些容器類涵蓋了各種不同的用途,從簡單的動態陣列到複雜的對映和集合。本章我們將主要學習關聯容器,主要包括 QMap
,QSet
和 QHash
,它們提供了鍵值對儲存和檢索的功能,允許通過鍵來快速查詢值。
QMap
是 Qt 中的有序關聯容器,用於儲存鍵值對,並按鍵的升序進行排序。以下是關於 QMap
的概述:
QMap
中的元素是有序的,按照鍵的升序進行排列。QMap
中是唯一的,不允許重複鍵。以下是關於 QMap
常用函數及其功能的總結:
函數 | 功能 |
---|---|
insert(const Key &key, const T &value) |
向 QMap 中插入鍵值對。 |
insertMulti(const Key &key, const T &value) |
向 QMap 中插入允許相同鍵的多個值。 |
remove(const Key &key) |
移除指定鍵的元素。 |
value(const Key &key) const |
返回指定鍵的值。 |
contains(const Key &key) const |
判斷是否包含指定鍵。 |
isEmpty() const |
判斷 QMap 是否為空。 |
size() const |
返回 QMap 中鍵值對的數量。 |
clear() |
清空 QMap 中的所有元素。 |
keys() const |
返回 QMap 中所有鍵的列表。 |
values() const |
返回 QMap 中所有值的列表。 |
begin() |
返回指向 QMap 開始位置的迭代器。 |
end() |
返回指向 QMap 結束位置的迭代器。 |
constBegin() const |
返回指向 QMap 開始位置的常數迭代器。 |
constEnd() const |
返回指向 QMap 結束位置的常數迭代器。 |
find(const Key &key) const |
返回指向 QMap 中指定鍵的迭代器。 |
lowerBound(const Key &key) const |
返回指向 QMap 中不小於指定鍵的第一個元素的迭代器。 |
upperBound(const Key &key) const |
返回指向 QMap 中大於指定鍵的第一個元素的迭代器。 |
count(const Key &key) const |
返回指定鍵的數量。 |
toStdMap() const |
將 QMap 轉換為 std::map 。 |
這些函數提供了對 QMap
中鍵值對的插入、刪除、查詢和遍歷等操作。根據需求選擇適當的函數以滿足操作要求。
正如如下程式碼所示,我們提供了QMap<QString,QString>
字典型別的關聯陣列,該陣列中一個鍵對映對應一個值,QMap容器是按照順序儲存的,如果專案中不在意順序可以使用QHash
容器,使用QHash
效率更高些。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QtGlobal>
#include <QMap>
#include <QMapIterator>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<QString,QString> map;
map["1001"] = "admin";
map["1002"] = "guest";
map.insert("1003","lyshark");
map.insert("1004","lucy");
// map.remove("1002");
// 根據鍵值對查詢屬性
std::cout << map["1002"].toStdString().data() << std::endl;
std::cout << map.value("1003").toStdString().data() << std::endl;
std::cout << map.key("admin").toStdString().data() << std::endl;
// 使用STL語法迭代列舉Map鍵值對
QMap<QString,QString>::const_iterator x;
for(x=map.constBegin();x != map.constEnd(); ++x)
{
std::cout << x.key().toStdString().data() << " : ";
std::cout << x.value().toStdString().data() << std::endl;
}
// 使用STL語法實現修改鍵值對
QMap<QString,QString>::iterator write_x;
write_x = map.find("1003");
if(write_x !=map.end())
write_x.value()= "you ary in";
// 使用QTglobal中自帶的foreach遍歷鍵值對
QString each;
// --> 單迴圈遍歷
foreach(const QString &each,map.keys())
{
std::cout << map.value(each).toStdString().data() << std::endl;
}
// --> 多回圈遍歷
foreach(const QString &each,map.uniqueKeys())
{
foreach(QString x,map.value(each))
{
std::cout << each.toStdString().data() << " : ";
std::cout << x.toStdString().data() << std::endl;
}
}
return a.exec();
}
上述程式碼是如何使用QMap
容器,其實還有一個QMultiMap
容器,該容器其實是QMap
的一個子集,用於處理多值對映的類,也就是說傳統QMap
只能是一對一的關係,而QMultiMap
則可以實現一個Key
對應多個Value
或者是反過來亦可,實現一對多的關係。
如果總結起來可以發現兩者的異同點;
QMap
中每個鍵都是唯一的,不允許重複鍵。QMap
中的元素是按鍵的升序排列的。QMultiMap
中可以包含重複的鍵,即多個鍵可以對映到相同的值。QMultiMap
中的元素是按鍵的升序排列的。QMap
中每個鍵都是唯一的,而 QMultiMap
允許重複的鍵。QMap
適用於需要鍵唯一的情況,而 QMultiMap
適用於允許鍵重複的情況。如下所示,展示瞭如何使用QMultiMap
實現一對多的對映關係;
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QList>
#include <QMultiMap>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMultiMap<QString,QString> mapA,mapB,mapC,mapD;
mapA.insert("lyshark","1000");
mapA.insert("lyshark","2000");
mapB.insert("admin","3000");
mapB.insert("admin","4000");
mapC.insert("admin","5000");
// 獲取到裡面的所有key=lyshark的值
QList<QString> ref;
ref = mapA.values("lyshark");
for(int x=0;x<ref.size();++x)
{
std::cout << ref.at(x).toStdString().data() << std::endl;
}
// 兩個key相同可相加後輸出
mapD = mapB + mapC;
ref = mapD.values("admin");
for(int x=0;x<ref.size();x++)
{
std::cout << ref.at(x).toStdString().data() << std::endl;
}
return a.exec();
}
QHash
是一個無序的關聯容器,它儲存鍵值對,但與 QMap
不同,QHash
不會對鍵進行排序。
鍵值對儲存: QHash
中的元素以鍵值對的形式儲存,但與 QMap
不同,QHash
中的元素是無序的。
無序性: QHash
中的元素是無序的,沒有特定的排列順序。
唯一鍵: 每個鍵在 QHash
中是唯一的,不允許重複鍵。
效能: 插入和查詢操作的平均複雜度是 O(1),適用於需要快速插入和查詢的場景。
以下是關於 QHash
常用函數及其功能的總結:
函數 | 功能 |
---|---|
insert(const Key &key, const T &value) |
向 QHash 中插入鍵值對。 |
insertMulti(const Key &key, const T &value) |
向 QHash 中插入允許相同鍵的多個值。 |
remove(const Key &key) |
移除指定鍵的元素。 |
value(const Key &key) const |
返回指定鍵的值。 |
contains(const Key &key) const |
判斷是否包含指定鍵。 |
isEmpty() const |
判斷 QHash 是否為空。 |
size() const |
返回 QHash 中鍵值對的數量。 |
clear() |
清空 QHash 中的所有元素。 |
keys() const |
返回 QHash 中所有鍵的列表。 |
values() const |
返回 QHash 中所有值的列表。 |
begin() |
返回指向 QHash 開始位置的迭代器。 |
end() |
返回指向 QHash 結束位置的迭代器。 |
constBegin() const |
返回指向 QHash 開始位置的常數迭代器。 |
constEnd() const |
返回指向 QHash 結束位置的常數迭代器。 |
find(const Key &key) const |
返回指向 QHash 中指定鍵的迭代器。 |
count(const Key &key) const |
返回指定鍵的數量。 |
unite(const QHash &other) |
合併兩個 QHash ,將 other 中的元素合併到當前 QHash 。 |
intersect(const QHash &other) |
保留兩個 QHash 中共有的元素,刪除其他元素。 |
subtract(const QHash &other) |
從當前 QHash 中移除與 other 共有的元素。 |
toStdHash() const |
將 QHash 轉換為 std::unordered_map 。 |
這些函數提供了對 QHash
中鍵值對的插入、刪除、查詢和遍歷等操作。根據需求選擇適當的函數以滿足操作要求。
QHash
與QMap
其實是一樣的,如果不需要對鍵值對進行排序那麼使用QHash
將會得到更高的效率,正是因為Hash
的無序,才讓其具備了更加高效的處理能力。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QHash>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QHash<QString, QString> hash;
hash["1001"] = "admin";
hash["1002"] = "guest";
hash.insert("1003", "lyshark");
hash.insert("1004", "lucy");
// hash.remove("1002");
// 根據鍵值對查詢屬性
std::cout << hash["1002"].toStdString().data() << std::endl;
std::cout << hash.value("1003").toStdString().data() << std::endl;
std::cout << hash.key("admin").toStdString().data() << std::endl;
// 使用STL語法迭代列舉Hash鍵值對
QHash<QString, QString>::const_iterator x;
for (x = hash.constBegin(); x != hash.constEnd(); ++x)
{
std::cout << x.key().toStdString().data() << " : ";
std::cout << x.value().toStdString().data() << std::endl;
}
// 使用STL語法實現修改鍵值對
QHash<QString, QString>::iterator write_x;
write_x = hash.find("1003");
if (write_x != hash.end())
write_x.value() = "you are in";
// 使用Qt中自帶的foreach遍歷鍵值對
QString each;
// --> 單迴圈遍歷
foreach (const QString &each, hash.keys())
{
std::cout << hash.value(each).toStdString().data() << std::endl;
}
// --> 多回圈遍歷
foreach (const QString &each, hash.uniqueKeys())
{
foreach (QString x, hash.values(each))
{
std::cout << each.toStdString().data() << " : ";
std::cout << x.toStdString().data() << std::endl;
}
}
return a.exec();
}
這裡需要說明一點,與QMap
一樣,QHash
也能夠使用QMultiHash
其操作上與QMultiMap
保持一致,此處讀者可自行嘗試。
QSet
是 Qt 中的無序關聯容器,類似於 C++ 標準庫的 std::unordered_set
。它主要用於儲存唯一值,而不關心元素的順序。以下是關於 QSet
的概述:
QSet
中的元素是無序的,沒有特定的排列順序。QSet
中是唯一的,不允許重複值。QMap
)更高。以下是關於 QSet
常用函數及其功能的總結:
函數 | 功能 |
---|---|
insert(const T &value) |
向 QSet 中插入元素。 |
contains(const T &value) const |
判斷是否包含指定元素。 |
remove(const T &value) |
移除指定元素。 |
isEmpty() const |
判斷 QSet 是否為空。 |
size() const |
返回 QSet 中元素的數量。 |
clear() |
清空 QSet 中的所有元素。 |
unite(const QSet &other) |
合併兩個 QSet ,將 other 中的元素合併到當前 QSet 。 |
intersect(const QSet &other) |
保留兩個 QSet 中共有的元素,刪除其他元素。 |
subtract(const QSet &other) |
從當前 QSet 中移除與 other 共有的元素。 |
begin() |
返回指向 QSet 開始位置的迭代器。 |
end() |
返回指向 QSet 結束位置的迭代器。 |
constBegin() const |
返回指向 QSet 開始位置的常數迭代器。 |
constEnd() const |
返回指向 QSet 結束位置的常數迭代器。 |
這些函數提供了對 QSet
中元素的插入、刪除、查詢和遍歷等操作。QSet
是一個無序容器,用於儲存唯一的元素。根據需求選擇適當的函數以滿足操作要求。
QSet 集合容器,是基於雜湊表(雜湊表)的集合模板,儲存順序同樣不定,查詢速度最快,其內部使用QHash
實現。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QSet>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSet<QString> set;
set << "dog" << "cat" << "tiger";
// 測試某值是否包含於集合
if(set.contains("cat"))
{
std::cout << "include" << std::endl;
}
return a.exec();
}
程式碼通過結合使用 QList
和 QMap
實現了資料的巢狀儲存。具體而言,通過在 QMap
中儲存鍵值對,其中鍵是時間字串,而值是包含浮點數資料的 QList
。這種結構使得可以方便地按時間檢索相關聯的資料集。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QtGlobal>
#include <QList>
#include <QMap>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<QString,QList<float>> map;
QList<float> ptr;
// 指定第一組資料
ptr.append(10.1);
ptr.append(12.5);
ptr.append(22.3);
map["10:10"] = ptr;
// 指定第二組資料
ptr.clear();
ptr.append(102.2);
ptr.append(203.2);
ptr.append(102.1);
map["11:20"] = ptr;
// 輸出所有的資料
QList<float> tmp;
foreach(QString each,map.uniqueKeys())
{
tmp = map.value(each);
std::cout << "Time: " << each.toStdString().data() << std::endl;
for(qint32 x=0;x<tmp.count();x++)
{
std::cout << tmp[x]<< std::endl;
}
}
return a.exec();
}
在範例中,兩組資料分別對應不同的時間鍵,每組資料儲存在相應的 QList
中。最後,通過迭代輸出了所有資料,以時間為鍵檢索相應的資料集,並將每個資料集中的浮點數逐個輸出。整體而言,這種資料結構的巢狀使用有助於組織和檢索多維度的資料。
通過使用 QList
儲存頭部資訊(Header)和相應的數值資訊(Values),然後通過迴圈迭代將兩個列表合併為一個 QMap
。在這個 QMap
中,頭部資訊作為鍵,而數值作為相應的值,形成了一個鍵值對應的字典結構。最後,通過 QMap
的鍵值對操作,輸出了特定字典中的資料。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QtGlobal>
#include <QList>
#include <QMap>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<QString> Header = {"MemTotal","MemFree","Cached","SwapTotal","SwapFree"};
QList<float> Values = {12.5,46.8,68,100.3,55.9};
QMap<QString,float> map;
// 將列表合併為一個字典
for(int x=0;x<Header.count();x++)
{
QString head = Header[x].toStdString().data();
float val = Values[x];
map[head] = val;
}
// 輸出特定字典中的資料
std::cout << map.key(100.3).toStdString().data() << std::endl;
std::cout << map.value("SwapTotal") << std::endl;
return a.exec();
}
整體而言,這樣的資料結構使得能夠更方便地按照特定的頭部資訊檢索相應的數值。
這段程式碼演示瞭如何使用 QMap
儲存鍵值對,並分別將鍵和值儲存到兩個 QList
中。首先,通過 Display
函數輸出了 QMap
中的鍵值對。
接著,通過 map.keys()
和 map.values()
分別獲取 QMap
中的所有鍵和值,將它們儲存到兩個 QList
中,並使用迴圈分別輸出了這兩個列表的內容。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QtGlobal>
#include <QList>
#include <QMap>
void Display(QMap<QString,float> map)
{
foreach(const QString &each,map.uniqueKeys())
{
std::cout << each.toStdString().data() << std::endl;
std::cout << map.value(each) << std::endl;
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<QString,float> map;
map["MemTotal"] = 12.5;
map["MemFree"] = 32.1;
map["Cached"] = 19.2;
Display(map);
QList<QString> map_key;
QList<float> map_value;
// 分別儲存起來
map_key = map.keys();
map_value = map.values();
// 輸出所有的key值
for(int x=0;x<map_key.count();x++)
{
std::cout << map_key[x].toStdString().data() << std::endl;
}
// 輸出所有的value值
for(int x=0;x<map_value.count();x++)
{
std::cout << map_value[x] << std::endl;
}
return a.exec();
}
實現對包含結構體 MyStruct
的 QList
進行排序,並輸出排序後的結果。首先,定義了一個包含整數的 QList
,通過 std::sort
函數按從大到小的順序對該列表進行排序,並使用 Display
函數輸出排序後的結果。
其次,定義結構體 MyStruct
,其中包含兩個成員變數 uuid
和 uname
。建立一個儲存該結構體的 QList
,並新增了幾個結構體物件。通過 devListSort
函數,以結構體的 uuid
成員進行排序,並使用迴圈輸出排序後的結果。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QtGlobal>
#include <QList>
struct MyStruct
{
int uuid;
QString uname;
};
void Display(QList<int> ptr)
{
foreach(const int &each,ptr)
std::cout << each << " ";
std::cout << std::endl;
}
// 由大到小排列
int compare(const int &infoA,const int &infoB)
{
return infoA > infoB;
}
// 針對結構體的排序方法
void devListSort(QList<MyStruct> *list)
{
std::sort(list->begin(),list->end(),[](const MyStruct &infoA,const MyStruct &infoB)
{
return infoA.uuid < infoB.uuid;
});
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 定義並對單一陣列排序
QList<int> list = {56,88,34,61,79,82,34,67,88,1};
std::sort(list.begin(),list.end(),compare);
Display(list);
// 定義並對結構體排序
QList<MyStruct> list_struct;
MyStruct ptr;
ptr.uuid=1005;
ptr.uname="admin";
list_struct.append(ptr);
ptr.uuid=1002;
ptr.uname = "guest";
list_struct.append(ptr);
ptr.uuid = 1000;
ptr.uname = "lyshark";
list_struct.append(ptr);
devListSort(&list_struct);
for(int x=0;x< list_struct.count();x++)
{
std::cout << list_struct[x].uuid << " ---> ";
std::cout << list_struct[x].uname.toStdString().data() << std::endl;
}
return a.exec();
}
上述這段程式碼演示瞭如何對一個包含整數的列表和一個包含結構體的列表進行排序,並輸出排序後的結果。在結構體排序的情況下,使用了自定義的排序方法 devListSort
,該方法按照結構體的 uuid
成員進行升序排序。