當我們談論程式設計中的資料結構時,順序容器是不可忽視的一個重要概念。順序容器是一種能夠按照元素新增的順序來儲存和檢索資料的資料結構。它們提供了簡單而直觀的方式來組織和管理資料,為程式設計師提供了靈活性和效能的平衡。
Qt 中提供了豐富的容器類,用於方便地管理和運算元據。這些容器類涵蓋了各種不同的用途,從簡單的動態陣列到複雜的對映和集合。本章我們將主要學習順序容器,順序容器是一組強大而靈活的資料結構,用於按照元素新增的順序儲存和管理資料。Qt提供了多種順序容器,每種都具有獨特的特性,這些容器包括向量、列表、佇列、棧等,每種都有特定的適用場景。
當然了STL標準模板中也存在這些容器,Qt 的容器類與標準模板庫(STL)中的容器類有些相似,但也有一些不同之處。以下是 Qt 容器類相對於STL的一些特點和優勢:
QExplicitlySharedDataPointer
)和不顯式共用兩種方式,方便在多執行緒應用中進行資料處理。QString
),以及一些便捷的成員函數,使得容器的使用更為方便。在某些特定的場景和需求下,STL 的容器類可能更適合使用。然而,在使用 Qt 框架的情況下,Qt 容器類通常能夠提供更好的整合和一些額外的特性。選擇使用哪種容器類取決於具體的專案需求和開發者的偏好。
QList
是 Qt 中常用的動態陣列類,它提供了動態大小的陣列,支援在列表的兩端和中間快速插入、刪除元素。適用於需要動態管理元素集合的場景,使得對列表的操作更加簡便。
以下是 QList
的一些常用函數:
函數 | 功能 |
---|---|
QList::QList() |
建構函式,建立一個空的 QList 物件。 |
QList::QList(const QList &other) |
複製建構函式,建立一個與給定列表相同的 QList 物件。 |
QList::append(const T &value) |
在列表末尾新增一個元素。 |
QList::prepend(const T &value) |
在列表開頭新增一個元素。 |
QList::replace(int i, const T &value) |
替換列表中索引為 i 的元素為給定的值。 |
QList::removeAt(int i) |
移除列表中索引為 i 的元素。 |
QList::removeOne(const T &value) |
移除列表中第一個匹配給定值的元素。 |
QList::removeAll(const T &value) |
移除列表中所有匹配給定值的元素。 |
QList::takeAt(int i) |
移除並返回列表中索引為 i 的元素。 |
QList::takeFirst() |
移除並返回列表中的第一個元素。 |
QList::takeLast() |
移除並返回列表中的最後一個元素。 |
QList::insert(int i, const T &value) |
在列表中索引為 i 的位置插入一個元素。 |
QList::contains(const T &value) const |
判斷列表中是否包含給定值。 |
QList::count(const T &value) const |
統計列表中匹配給定值的元素數量。 |
QList::indexOf(const T &value, int from = 0) const |
返回給定值在列表中的第一個匹配項的索引,從指定位置 from 開始搜尋。 |
QList::lastIndexOf(const T &value, int from = -1) const |
返回給定值在列表中的最後一個匹配項的索引,從指定位置 from 開始反向搜尋。 |
QList::isEmpty() const |
判斷列表是否為空。 |
QList::size() const |
返回列表中元素的數量。 |
QList::clear() |
清空列表,移除所有元素。 |
QList::operator=() |
過載賦值運運算元,將一個列表賦值給另一個列表。 |
QList::operator==() |
過載相等運運算元,判斷兩個列表是否相等。 |
QList::operator!=() |
過載不等運運算元,判斷兩個列表是否不相等。 |
以上是 QList
的一些常用函數及其功能,這些函數允許開發者對列表進行新增、刪除、替換、查詢等操作,以滿足不同場景的需求。
QList
是動態大小的陣列,可以根據需要自動調整大小。QList
是泛型容器,可以儲存任意型別的資料。QList
提供了雙向迭代器,可以方便地從前往後或從後往前遍歷列表。如下所示的程式碼中我定義了兩個QList
容器,分別是StringPtrA
和StringPtrB
通過使用不同的容器操作函數對其進行簡單的增加插入替換刪除和移動操作,如下程式碼所示;
#include <QCoreApplication>
#include <iostream>
#include <QList>
void Display(QList<QString> &ptr)
{
std::cout << "-----------------------------" << std::endl;
for(qint32 x=0;x<ptr.count();x++)
{
// std::cout << ptr[x].toStdString().data() << std::endl;
std::cout << (ptr.at(x)).toStdString().data() << std::endl;
}
std::cout << std::endl;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<QString> StringPtrA;
QList<QString> StringPtrB;
// 新增三個成員
StringPtrA.append("admin");
StringPtrA.append("guest");
StringPtrA.append("lyshark");
Display(StringPtrA);
// 在首部插入hanter
StringPtrA.prepend("hanter");
Display(StringPtrA);
// 在第0的位置插入lucy
StringPtrA.insert(0,QString("lucy"));
Display(StringPtrA);
// 替換原來的admin為全拼
StringPtrA.replace(1,"Administrator");
Display(StringPtrA);
// 刪除第0個元素
StringPtrA.removeAt(0);
Display(StringPtrA);
// 刪除首部和尾部
StringPtrA.removeFirst();
StringPtrA.removeLast();
// 移動兩個變數
StringPtrA.move(0,1);
Display(StringPtrA);
// 將兩個list容器對調交換
StringPtrB = {"youtube","facebook"};
StringPtrA.swap(StringPtrB);
Display(StringPtrA);
return a.exec();
}
上述程式碼我們只是對字串進行了連結串列管理,其實Qt中支援管理結構體,首先要定義一個特有的結構體MyStruct
當結構體被賦值後就可以像陣列一樣靈活的運算元據,當然在使用結構體時我們傳入的應該是QList<MyStruct>
結構體的名字,在遍歷時可以有三種方式,第一種時傳統的迴圈依次輸出元素,這裡我們說說使用QListIterator
和QMutableListIterator
來輸出元素的區別。
#include <QCoreApplication>
#include <iostream>
#include <QList>
#include <QListIterator>
#include <QMutableListIterator>
struct MyStruct
{
qint32 uid;
QString uname;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<MyStruct> ptr;
MyStruct str_ptr;
str_ptr.uid = 1001;
str_ptr.uname = "admin";
ptr.append(str_ptr);
str_ptr.uid = 1002;
str_ptr.uname = "guest";
ptr.append(str_ptr);
// 使用傳統方式遍歷資料
for(qint32 x=0;x<ptr.count();x++)
{
std::cout << ptr.at(x).uid << std::endl;
std::cout << ptr[x].uname.toStdString().data() << std::endl;
}
// 使用唯讀迭代器遍歷
QListIterator<MyStruct> x(ptr);
while(x.hasNext())
{
// peeknext讀取下一個節點,但不影響指標變化
std::cout << x.peekNext().uid << std::endl;
std::cout << (x.peekNext().uname).toStdString().data() << std::endl;
// 最後將x指標指向下一個資料
x.next();
}
// 使用讀寫迭代器:如果uid=1002則將guest改為lyshark
QMutableListIterator<MyStruct> y(ptr);
while(y.hasNext())
{
// y.peekNext().uid = 9999;
if(y.peekNext().uid == 1002)
{
y.peekNext().uname = "lyshark";
}
y.next();
}
return a.exec();
}
其實QListIterator
和 QMutableListIterator
都是用於遍歷 QList
容器的迭代器類。區別是QListIterator
是一個唯讀迭代器,用於遍歷 QList
容器中的元素。它提供了一個方便的方式來存取容器中的元素,支援前向和後向遍歷。而QMutableListIterator
是一個可變迭代器,除了支援讀取元素外,還允許修改 QList
中的元素。它提供了修改元素的介面,使得在遍歷的同時可以對容器進行修改。
QListIterator(const QList<T> &list)
: 建構函式,用於初始化迭代器並關聯到給定的 QList
。hasNext() const
: 檢查是否有下一個元素。next()
: 返回當前元素並將迭代器移動到下一個元素。peekNext() const
: 返回當前元素但不移動迭代器。toFront()
: 將迭代器移動到列表的第一個元素。toBack()
: 將迭代器移動到列表的最後一個元素。QMutableListIterator(QList<T> &list)
: 建構函式,用於初始化可變迭代器並關聯到給定的 QList
。hasNext() const
: 檢查是否有下一個元素。next()
: 返回當前元素並將迭代器移動到下一個元素。peekNext() const
: 返回當前元素但不移動迭代器。toFront()
: 將迭代器移動到列表的第一個元素。toBack()
: 將迭代器移動到列表的最後一個元素。remove()
: 移除迭代器當前位置的元素。setValue(const T &value)
: 將迭代器當前位置的元素設定為給定值。這兩個迭代器類提供了方便而靈活的方式來遍歷和操作 QList
中的元素,根據需要選擇合適的迭代器。
QLinkedList
是 Qt 中的雙向連結串列實現,與 QList
不同,它不是基於陣列的動態容器,而是基於連結串列的資料結構。QLinkedList
提供了連結串列特有的靈活性,適用於需要在任意位置高效插入和刪除元素的場景。在一些存取元素的場景中,由於連結串列的非連續儲存特性,可能比陣列容器的存取效率稍低。選擇使用 QLinkedList
還是其他容器,取決於具體的使用需求。
以下是 QLinkedList
的一些常用函數:
函數 | 功能 |
---|---|
QLinkedList::QLinkedList() |
建構函式,建立一個空的 QLinkedList 物件。 |
QLinkedList::QLinkedList(const QLinkedList &other) |
複製建構函式,建立一個與給定連結串列相同的 QLinkedList 物件。 |
QLinkedList::append(const T &value) |
在連結串列末尾新增一個元素。 |
QLinkedList::prepend(const T &value) |
在連結串列開頭新增一個元素。 |
QLinkedList::replace(const_iterator before, const T &value) |
替換連結串列中給定迭代器位置的元素為給定的值。 |
QLinkedList::remove(const T &value) |
移除連結串列中所有匹配給定值的元素。 |
QLinkedList::removeOne(const T &value) |
移除連結串列中第一個匹配給定值的元素。 |
QLinkedList::removeAt(int i) |
移除連結串列中索引為 i 的元素。 |
QLinkedList::takeAt(int i) |
移除並返回連結串列中索引為 i 的元素。 |
QLinkedList::takeFirst() |
移除並返回連結串列中的第一個元素。 |
QLinkedList::takeLast() |
移除並返回連結串列中的最後一個元素。 |
QLinkedList::insert(const_iterator before, const T &value) |
在連結串列中給定迭代器位置插入一個元素。 |
QLinkedList::contains(const T &value) const |
判斷連結串列中是否包含給定值。 |
QLinkedList::count(const T &value) const |
統計連結串列中匹配給定值的元素數量。 |
QLinkedList::indexOf(const T &value) const |
返回給定值在連結串列中的第一個匹配項的索引。 |
QLinkedList::lastIndexOf(const T &value) const |
返回給定值在連結串列中的最後一個匹配項的索引。 |
QLinkedList::isEmpty() const |
判斷連結串列是否為空。 |
QLinkedList::size() const |
返回連結串列中元素的數量。 |
QLinkedList::clear() |
清空連結串列,移除所有元素。 |
QLinkedList::begin() |
返回指向連結串列第一個元素的迭代器。 |
QLinkedList::end() |
返回指向連結串列最後一個元素之後的迭代器。 |
QLinkedList
提供了與 QList
類似的操作,但由於其基於雙向連結串列實現,特別適合於需要頻繁插入和刪除操作的場景。在使用上,QLinkedList
提供了一些額外的函數,如 replace
、insert
等,可以更方便地操作連結串列中的元素。
QLinkedList
使用雙向連結串列結構,每個節點儲存一個元素以及指向前後節點的指標,支援高效的插入和刪除操作。QLinkedList
是泛型容器,可以儲存任意型別的資料。QLinkedList
提供了雙向迭代器,可以方便地從前往後或從後往前遍歷連結串列。QLinkeList其實就是動態連結串列結構,資料的儲存非連續,存取時無法直接使用下標定位,只能通過迭代器迭代尋找,這是其與QList
的本質區別,其引數定義與QList
基本一致,在使用上並沒有本質上的區別。
#include <QCoreApplication>
#include <iostream>
#include <QLinkedList>
#include <QLinkedListIterator>
#include <QMutableLinkedListIterator>
struct MyStruct
{
qint32 uid;
QString uname;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QLinkedList<MyStruct> ptr;
MyStruct str_ptr;
str_ptr.uid = 1001;
str_ptr.uname = "admin";
ptr.append(str_ptr);
str_ptr.uid = 1002;
str_ptr.uname = "guest";
ptr.append(str_ptr);
// 使用唯讀迭代器遍歷: 從前向後遍歷
QLinkedListIterator<MyStruct> x(ptr);
while(x.hasNext())
{
std::cout << x.peekNext().uid << std::endl;
x.next();
}
// 使用唯讀迭代器遍歷: 從後向前遍歷
for(x.toBack();x.hasPrevious();x.previous())
{
std::cout << x.peekPrevious().uid << std::endl;
}
// 使用STL風格的迭代器遍歷
QLinkedList<MyStruct>::iterator y;
for(y=ptr.begin();y!=ptr.end();++y)
{
std::cout << (*y).uid << std::endl;
}
// STL風格的唯讀迭代器
QLinkedList<MyStruct>::const_iterator z;
for(z=ptr.constBegin();z!=ptr.constEnd();++z)
{
std::cout <<((*z).uname).toStdString().data()<< std::endl;
}
// 使用讀寫迭代器: 動態生成列表,每次對二取餘
QLinkedList<int> Number = {1,2,3,4,5,6,7,8,9,10};
QMutableLinkedListIterator<int> item(Number);
// --> 從前向後輸出一次
for(item.toFront();item.hasNext();item.next())
std::cout << item.peekNext() << std::endl;
// --> 將指標移動到最後然後判斷
for(item.toBack();item.hasPrevious();)
{
if(item.previous() % 2==0)
item.remove();
else
item.setValue(item.peekNext() * 10);
}
// --> 最後輸出出相加後的結果
for(item.toFront();item.hasNext();)
{
std::cout << item.peekNext() << std::endl;
item.next();
}
return a.exec();
}
QVector
是Qt中的動態陣列類,它提供了動態大小的陣列,並在內部使用指標陣列進行儲存。QVector
是一個靈活的動態陣列類,適用於需要動態管理元素集合的場景,同時由於其連續儲存的特性,在存取元素的效率上相對較高。
以下是 QVector
的一些常用函數:
函數 | 功能 |
---|---|
QVector::QVector() |
建構函式,建立一個空的 QVector 物件。 |
QVector::QVector(int size) |
建構函式,建立一個包含 size 個元素的 QVector 物件。 |
QVector::QVector(int size, const T &value) |
建構函式,建立一個包含 size 個元素,每個元素都是給定值的 QVector 物件。 |
QVector::QVector(const QVector &other) |
複製建構函式,建立一個與給定向量相同的 QVector 物件。 |
QVector::append(const T &value) |
在向量末尾新增一個元素。 |
QVector::prepend(const T &value) |
在向量開頭新增一個元素。 |
QVector::replace(int i, const T &value) |
替換向量中索引為 i 的元素為給定的值。 |
QVector::removeAt(int i) |
移除向量中索引為 i 的元素。 |
QVector::removeOne(const T &value) |
移除向量中第一個匹配給定值的元素。 |
QVector::remove(const T &value) |
移除向量中所有匹配給定值的元素。 |
QVector::takeAt(int i) |
移除並返回向量中索引為 i 的元素。 |
QVector::takeFirst() |
移除並返回向量中的第一個元素。 |
QVector::takeLast() |
移除並返回向量中的最後一個元素。 |
QVector::insert(int i, const T &value) |
在向量中索引為 i 的位置插入一個元素。 |
QVector::fill(const T &value, int size = -1) |
使用給定值填充向量,如果指定了 size ,則填充到指定大小。 |
QVector::contains(const T &value) const |
判斷向量中是否包含給定值。 |
QVector::count(const T &value) const |
統計向量中匹配給定值的元素數量。 |
QVector::indexOf(const T &value, int from = 0) const |
返回給定值在向量中的第一個匹配項的索引,從指定位置 from 開始搜尋。 |
QVector::lastIndexOf(const T &value, int from = -1) const |
返回給定值在向量中的最後一個匹配項的索引,從指定位置 from 開始反向搜尋。 |
QVector::isEmpty() const |
判斷向量是否為空。 |
QVector::size() const |
返回向量中元素的數量。 |
QVector::clear() |
清空向量,移除所有元素。 |
QVector::resize(int size) |
更改向量的大小,如果新大小大於當前大小,會用預設值填充。 |
QVector::reserve(int size) |
預留空間以容納指定數量的元素,可提高插入操作的效能。 |
QVector::squeeze() |
釋放向量佔用的多餘空間。 |
QVector
提供了類似於 QList
的操作,但由於其底層使用連續儲存,因此在某些情況下效能更高。開發者可以根據具體的需求選擇適合的容器。
QVector
是動態大小的陣列,可以根據需要自動調整大小。QLinkedList
不同,QVector
的元素在記憶體中是連續儲存的,這有助於提高存取效率。QVector
是泛型容器,可以儲存任意型別的資料。QVector
在記憶體中儲存連續的資料,類似於 C++ 中的 std::vector
。該容器的使用與Qlist
完全一致,但讀取效能要比Qlist
更高,但在插入時速度最慢。
#include <QCoreApplication>
#include <iostream>
#include <QVector>
#include <QVectorIterator>
#include <QMutableVectorIterator>
struct MyStruct
{
qint32 uid;
QString uname;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QVector<MyStruct> ptr;
MyStruct str_ptr;
str_ptr.uid = 1001;
str_ptr.uname = "admin";
ptr.append(str_ptr);
str_ptr.uid = 1002;
str_ptr.uname = "guest";
ptr.append(str_ptr);
// 使用傳統方式遍歷
for(qint32 x=0;x<ptr.count();x++)
{
std::cout << ptr.at(x).uid << std::endl;
std::cout << ptr[x].uname.toStdString().data() << std::endl;
}
// 使用唯讀迭代器遍歷: C++ STL寫法
QVector<MyStruct>::const_iterator item;
for(item = ptr.begin();item != ptr.end(); ++item)
{
std::cout << (*item).uid << std::endl;
std::cout << (*item).uname.toStdString().data() << std::endl;
}
// 使用讀寫迭代器修改: C++ STL寫法
QVector<MyStruct>::iterator write_item;
for(write_item = ptr.begin();write_item !=ptr.end();++write_item)
{
if((*write_item).uid == 1001)
{
(*write_item).uname = "xxxx";
}
std::cout << (*write_item).uid << std::endl;
std::cout << (*write_item).uname.toStdString().data() << std::endl;
}
return a.exec();
}
QVector
和 QList
在介面上非常相似,可以使用相同的函數進行元素的存取、插入和刪除等操作。QVector
的元素在記憶體中是連續儲存的,因此在順序存取時,QVector
的效能通常比 QList
更高。但在中間插入元素時,QVector
的效能可能較差,因為需要移動插入點之後的所有元素。QVector
適用於需要頻繁進行順序存取而較少進行中間插入操作的場景,例如對大量資料進行順序處理的情況。QStack
是 Qt 中的棧容器,它提供了棧(LIFO)的資料結構。該容器用於需要滿足後進先出規則的場景,例如在演演算法實現中,或者在某些資料處理過程中需要臨時儲存和恢復狀態。
以下是 QStack
的一些常用函數:
函數 | 功能 |
---|---|
QStack::QStack() |
建構函式,建立一個空的 QStack 物件。 |
QStack::QStack(const QStack &other) |
複製建構函式,建立一個與給定棧相同的 QStack 物件。 |
QStack::push(const T &value) |
在棧頂壓入一個元素。 |
QStack::pop() |
彈出棧頂的元素。 |
QStack::top() const |
返回棧頂的元素,不彈出。 |
QStack::isEmpty() const |
判斷棧是否為空。 |
QStack::size() const |
返回棧中元素的數量。 |
QStack::clear() |
清空棧,移除所有元素。 |
QStack::operator=() |
過載賦值運運算元,將一個棧賦值給另一個棧。 |
QStack::operator==() |
過載相等運運算元,判斷兩個棧是否相等。 |
QStack::operator!=() |
過載不等運運算元,判斷兩個棧是否不相等。 |
QStack
是一個後進先出(LIFO)的棧,提供了壓棧、彈棧等基本操作。棧是一種常見的資料結構,可以用於需要遵循後進先出原則的場景,例如遞迴函數呼叫時的儲存函數呼叫資訊等。
QStack
是棧的實現,它遵循後進先出(Last In, First Out,LIFO)的原則。QStack
是泛型容器,可以儲存任意型別的資料。QStack
提供的介面限制在棧頂進行插入和刪除操作,不允許在中間或底部插入或刪除元素。#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QStack>
#include <QQueue>
struct MyStruct
{
qint32 uid;
QString uname;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 定義並彈出QString型別資料
QStack<QString> stack;
stack.push("admin");
stack.push("guest");
std::cout << (stack.top()).toStdString().data()<<std::endl;
while(!stack.isEmpty())
{
std::cout << (stack.pop()).toStdString().data() << std::endl;
}
// 定義並彈出一個結構型別資料
QStack<MyStruct> struct_stack;
MyStruct ptr;
ptr.uid = 1001;
ptr.uname = "admin";
struct_stack.push(ptr);
ptr.uid = 1002;
ptr.uname = "guest";
struct_stack.push(ptr);
// 分別彈出資料並輸出
while(!struct_stack.isEmpty())
{
MyStruct ref;
ref = struct_stack.pop();
std::cout << "uid = " << ref.uid << std::endl;
std::cout << "uname = " << ref.uname.toStdString().data() << std::endl;
}
return a.exec();
}
QQueue
是 Qt 中的佇列容器,它提供了佇列(FIFO)的資料結構。QQueue
可以用於需要滿足先進先出規則的場景,例如在任務排程、資料緩衝等應用中。
以下是 QQueue
的一些常用函數:
函數 | 功能 |
---|---|
QQueue::QQueue() |
建構函式,建立一個空的 QQueue 物件。 |
QQueue::QQueue(const QQueue &other) |
複製建構函式,建立一個與給定佇列相同的 QQueue 物件。 |
QQueue::enqueue(const T &value) |
在佇列尾部插入一個元素。 |
QQueue::dequeue() |
移除佇列頭部的元素。 |
QQueue::head() const |
返回佇列頭部的元素,不移除。 |
QQueue::isEmpty() const |
判斷佇列是否為空。 |
QQueue::size() const |
返回佇列中元素的數量。 |
QQueue::clear() |
清空佇列,移除所有元素。 |
QQueue::operator=() |
過載賦值運運算元,將一個佇列賦值給另一個佇列。 |
QQueue::operator==() |
過載相等運運算元,判斷兩個佇列是否相等。 |
QQueue::operator!=() |
過載不等運運算元,判斷兩個佇列是否不相等。 |
QQueue
是一個先進先出(FIFO)的佇列,提供了入隊、出隊等基本操作。佇列常用於需要按照先後順序處理元素的場景,例如任務佇列、訊息佇列等。
QQueue
是佇列的實現,它遵循先進先出(First In, First Out,FIFO)的原則。QQueue
是泛型容器,可以儲存任意型別的資料。QQueue
提供的介面限制在佇列的前端進行插入,佇列的後端進行刪除操作。佇列就是先進後出,在使用上與普通容器保持一致,只是佇列的可用方法會更少一些。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QQueue>
struct MyStruct
{
qint32 uid;
QString uname;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QQueue<MyStruct> ptr;
MyStruct queue_ptr;
// 實現對結構體的入隊
queue_ptr.uid = 1001;
queue_ptr.uname = "admin";
ptr.enqueue(queue_ptr);
queue_ptr.uid = 1002;
queue_ptr.uname = "guest";
ptr.enqueue(queue_ptr);
// 實現對結構體的出隊
while(!ptr.isEmpty())
{
MyStruct ref;
ref = ptr.dequeue();
std::cout << "uid = " << ref.uid << std::endl;
std::cout << "uname = " << ref.uname.toStdString().data() << std::endl;
}
return a.exec();
}