目录
1.容器类概述
2.顺序容器类
2.1 QList
2.2 QLinkedList
2.3 QVector
2.4 QStack
2.5 QQueue
3.关联容器类
3.1 QSet
3.2 QMap
3.3 QMultiMap
3.4 QHash
3.5 QMuItiHash
1.容器类概述
- Qt提供了多个基于模板的容器类,这些容器类可以用于存储指定类型的数据项。
- Qt的容器类比标准模板库(STL)中的容器类更轻巧、安全和易于使用。这些容器类是隐式共享和可重入的,而且它们进行了速度和存储优化,因此可以减少可执行文件的大小。此外,它们还是线程安全的,也就是说它们作为只读容器时可被多个线程访问。
- Qt的容器类分为顺序容器(sequentialcontainers)和关联容器(associativecontainers)。
- 容器迭代类用于遍历容器里的数据项,有Java类型的迭代类和STL类型的迭代类。Java类型的迭代类易于使用,提供高级功能,而STL类型的迭代类效率更高一些。Qt还提供了foreach宏用于遍历容器内的所有数据项。
2.顺序容器类
2.1 QList
//基本数据类型QList<int> integerList;QList<QDate> dateList;//存储QObject对象的地址QList <QWidget *> ptr_widgets;QList <QObject *> ptr_objects;
QList<QString> list = { "one", "two", "three" };QWidget * widget1 = new QWidget();QWidget * widget2 = new QWidget();QList<QWidget *> ptr_widgets = {widget1, widget2};
1. 增加节点insert():插入节点到append():尾部添加节点prepend() :头部添加节点operator <<():尾部添加节点或链表operator+=():尾部添加节点2. 删除节点removeAt():删除节点removeFirst():删除头节点removeLast():删除尾节点3. 移动节点move():链表内移动节点位置swap():俩个链表交换值(其实交换一下地址映射就能实现)4. 修改节点值replace():替换链表内的节点值
QList是有序的链表,可以通过索引来得到。1. operator [ ] 数组索引符:这个和普通数组一样的使用 [ ] 访问下标方法一致2. at() 函数:也是通过索引值,也即是下标方式Qt 推荐使用at()函数,这样的效率更好,因为 at()函数不会发生 深拷贝 ,而另外一种方式会。QList还提供了一些快捷的 索引 + 返回索引节点 + 删除原索引节点,也就是组合的功能;但是这个是 take…不是get…这样的,这就意味着,这个其实是剪掉一个节点,并返回。3. takeAt():取得在指定位置的节点4. takeFirst():取得头节点 ;等价【takeAt(0)】5. takeLast():取得尾节点
contains():是否包含节点xxxcount():对指定节点值计数isEmpty():链表为空size():链表大小indexOf():节点位置
2.2 QLinkedList
QLinkedList<T>是链式列表(linked-list)(双向链表容器类),数据项不是用连续的内存存储的,它基于迭代器访问数据项,并且插入和删除数据项的操作时间相同。除了不提供基于下标索引的数据项访问外,QLinkedList的其他接口函数与QList基本相同。
(1)重要特性如下:
-
动态大小:QLinkedList 的大小是动态的,可以根据需要轻松添加或删除元素。这使得它在处理具有不确定大小的数据集时非常有用。
-
双向遍历:与 QVector 和 QList 不同,QLinkedList 允许从头到尾以及从尾到头的双向遍历。这种遍历方式在某些场景下会非常有用。
-
高效的插入和删除操作:在链表的中间插入或删除元素的时间复杂度为 O(1)。这使得 QLinkedList 在需要频繁插入和删除元素的场景中,具有优势。
-
不需要连续内存:与 QVector 和 QList 相比,QLinkedList 的元素不需要存储在连续的内存空间中。这意味着在内存碎片化的情况下,QLinkedList 可能更容易分配内存。
(2)常用接口
构造函数和析构函数:
-
QLinkedList(): 创建一个空的 QLinkedList。
-
QLinkedList(const QLinkedList<T> &other): 复制构造函数,用另一个 QLinkedList 对象来创建一个新的对象。
-
~QLinkedList(): 析构函数,用于释放资源。
容量相关接口:
-
bool isEmpty() const: 返回链表是否为空。
-
int size() const: 返回链表中元素的数量。
元素访问接口:
-
T &first(): 返回链表中第一个元素的引用。
-
const T &first() const: 返回链表中第一个元素的常量引用。
-
T &last(): 返回链表中最后一个元素的引用。
-
const T &last() const: 返回链表中最后一个元素的常量引用。
修改接口:
-
void append(const T &value): 在链表末尾添加一个元素。
-
void prepend(const T &value): 在链表开头添加一个元素。
-
void insert(int i, const T &value): 在链表的指定位置插入一个元素。
-
void removeFirst(): 移除链表中的第一个元素。
-
void removeLast(): 移除链表中的最后一个元素。
-
bool removeOne(const T &value): 移除链表中第一个与指定值相等的元素,如果成功移除则返回 true,否则返回 false。
-
int removeAll(const T &value): 移除链表中所有与指定值相等的元素,返回移除的元素个数。
-
void clear(): 清空链表。
查找接口:
-
bool contains(const T &value) const: 检查链表是否包含指定值的元素。
-
int count(const T &value) const: 返回链表中指定值的元素个数。
-
int indexOf(const T &value, int from = 0) const: 返回链表中指定值的第一个元素的索引,如果未找到则返回 -1。
-
int lastIndexOf(const T &value, int from = -1) const: 返回链表中指定值的最后一个元素的索引,如果未找到则返回 -1。
迭代器:
-
iterator begin(): 返回指向链表第一个元素的迭代器。
-
const_iterator begin() const: 返回指向链表第一个元素的常量迭代器。
-
iterator end(): 返回指向链表末尾的迭代器。
-
const_iterator end() const 返回指向链表末尾的常量迭代器。
-
const_iterator cbegin() const: 返回指向链表第一个元素的常量迭代器。
-
const_iterator cend() const: 返回指向链表末尾的常量迭代器。
-
reverse_iterator rbegin(): 返回指向链表最后一个元素的反向迭代器。
-
const_reverse_iterator rbegin() const: 返回指向链表最后一个元素的常量反向迭代器。
-
reverse_iterator rend(): 返回指向链表起始位置之前的反向迭代器。
-
const_reverse_iterator rend() const: 返回指向链表起始位置之前的常量反向迭代器。
-
const_reverse_iterator crbegin() const: 返回指向链表最后一个元素的常量反向迭代器。
-
const_reverse_iterator crend() const: 返回指向链表起始位置之前的常量反向迭代器。
比较操作:
-
bool operator==(const QLinkedList<T> &other) const: 判断两个链表是否相等(元素数量和对应元素相等)。
-
bool operator!=(const QLinkedList<T> &other) const: 判断两个链表是否不等。
赋值操作:
-
QLinkedList<T> &operator=(const QLinkedList<T> &other): 为当前链表赋值另一个链表的内容。
其他接口:
-
void swap(QLinkedList<T> &other): 交换两个链表的内容。
注意:在使用 QLinkedList 时,应确保所存储的元素类型支持复制构造函数和赋值操作。对于大型数据结构,如果不需要频繁插入和删除元素,可以考虑使用 QVector 以获得更好的内存管理和性能。
(3)QLinkedList 常见操作
插入元素:
QLinkedList<int> list;
list.append(1);
list.append(2);
list.append(3);
list.prepend(0); // 在开始处插入元素
删除元素:
list.removeAll(1); // 删除所有值为 1 的元素
list.removeFirst(); // 删除第一个元素
list.removeLast(); // 删除最后一个元素
访问元素:
int first = list.first(); // 获取第一个元素
int last = list.last(); // 获取最后一个元素
查找元素:
QLinkedList<int>::iterator it = std::find(list.begin(), list.end(), 2); // 查找值为 2 的元素
if (it != list.end()) {
qDebug() << "Found:" << *it;
}
反转链表(C++14 及以上):
std::reverse(list.begin(), list.end());
排序链表:
std::sort(list.begin(), list.end()); // 默认升序排序
自定义排序:
auto descendingOrder = [](int a, int b) { return a > b; };
std::sort(list.begin(), list.end(), descendingOrder); // 降序排序
迭代器遍历:
QLinkedList<int>::iterator it;
for (it = list.begin(); it != list.end(); ++it) {
qDebug() << *it;
}
使用 Java 风格迭代器:
QLinkedListIterator<int> it(list);
while (it.hasNext()) {
qDebug() << it.next();
}
使用常量迭代器(只读访问):
QLinkedList<int>::const_iterator cit;
for (cit = list.constBegin(); cit != list.constEnd(); ++cit) {
qDebug() << *cit;
}
2.3 QVector
QVector<T>提供动态数组的功能,以下标索引访问数据。
QVector的函数接口与QList几乎完全相同,QVector<T>的性能比QList<T>更高,因为
QVector<T>的数据项是连续存储的。
(1)常用接口
构造函数:
-
QVector():创建一个空的 QVector 容器。
-
QVector(int size):创建一个指定大小的 QVector 容器。
-
QVector(int size, const T &value):创建一个指定大小的 QVector 容器,并用给定值填充。
-
QVector(const QVector<T> &other):复制构造函数,用另一个 QVector 容器创建一个新的 QVector 容器。
元素访问:
-
T &operator[](int i):通过索引访问元素,返回指定索引处的元素的引用。
-
const T &operator[](int i) const:以只读方式通过索引访问元素。
-
T &at(int i):通过索引访问元素,会检查索引是否越界。
-
T &front():返回容器中的第一个元素的引用。
-
const T &front() const:以只读方式返回容器中的第一个元素。
-
T &back():返回容器中的最后一个元素的引用。
-
const T &back() const:以只读方式返回容器中的最后一个元素。
容量和大小:
-
bool isEmpty() const:判断容器是否为空。
-
int size() const:获取容器中元素的数量。
-
int capacity() const:获取容器的容量。
-
void reserve(int size):预分配指定数量的元素空间,提高性能。
-
void squeeze():释放未使用的容量,将容量调整为实际元素数量。
修改容器:
-
void clear():清空容器中的所有元素。
-
void resize(int size):调整容器的大小。
-
void fill(const T &value, int size = -1):用给定值填充容器,可以指定填充个数。
-
void append(const T &value):在容器末尾添加一个元素。
-
void prepend(const T &value):在容器开头添加一个元素。
-
void insert(int i, const T &value):在指定位置插入一个元素。
-
void replace(int i, const T &value):替换指定位置的元素。
-
void remove(int i):移除指定位置的元素。
-
void remove(int i, int count):从指定位置开始移除指定数量的元素。
-
void removeAll(const T &value):移除容器中所有等于给定值的元素。
-
bool removeOne(const T &value):移除容器中第一个等于给定值的元素。
查找:
-
int indexOf(const T &value, int from = 0) const:从指定位置开始查找给定值的元素,返回第一个找到的元素的索引。
-
int lastIndexOf(const T &value, int from = -1) const:从指定位置开始向前查找给定值的元素,返回第一个找到的元素的索引。
-
bool contains(const T &value) const:判断容器中是否包含给定值的元素。
-
int count(const T &value) const:计算容器中给定值的元素的个数。
排序:
-
void sort(Qt::SortOrder order = Qt::AscendingOrder):对容器中的元素进行排序,可以指定升序或降序。
-
void stableSort(Qt::SortOrder order = Qt::AscendingOrder):对容器中的元素进行稳定排序,可以指定升序或降序。
迭代器:
-
iterator begin():返回容器的起始迭代器。
-
const_iterator begin() const:返回容器的只读起始迭代器。
-
iterator end():返回容器的结束迭代器。
-
const_iterator end() const:返回容器的只读结束迭代器。
比较操作符:
-
bool operator==(const QVector<T> &other) const:判断两个 QVector 容器是否相等,元素数量和值都相等时为 true。
-
bool operator!=(const QVector<T> &other) const:判断两个 QVector 容器是否不相等。
其他功能:
-
QVector<T> &operator=(const QVector<T> &other):赋值操作符,将一个 QVector 容器赋值给另一个。
-
QVector<T> mid(int pos, int length = -1) const:获取容器中指定范围的元素,返回一个新的 QVector 容器。
-
void swap(QVector<T> &other):交换两个 QVector 容器的内容。
(2)QVector示例
#include <QVector>
#include <QDebug>int main()
{// 创建一个 QVector 容器,并添加元素QVector<int> vec;vec.append(3);vec.append(1);vec.append(4);vec.append(2);qDebug() << "Original QVector:";for (int i = 0; i < vec.size(); ++i) {qDebug() << vec.at(i);}// 使用排序功能vec.sort(Qt::AscendingOrder);qDebug() << "Sorted QVector:";for (int i = 0; i < vec.size(); ++i) {qDebug() << vec.at(i);}// 插入元素vec.insert(1, 8); // 在索引 1 位置插入值 8qDebug() << "QVector after inserting 8 at index 1:";for (int i = 0; i < vec.size(); ++i) {qDebug() << vec.at(i);}// 删除元素vec.remove(2); // 删除索引 2 处的元素qDebug() << "QVector after removing the element at index 2:";for (int i = 0; i < vec.size(); ++i) {qDebug() << vec.at(i);}// 查找元素int index = vec.indexOf(4);if (index != -1) {qDebug() << "Element 4 found at index:" << index;} else {qDebug() << "Element 4 not found";}return 0;
}
2.4 QStack
QStack<T>是提供类似于堆栈的后入先出(LIFO)操作的容器类,可以存储任何类型的数据,QStack使用动态数组来实现数据的存储,push()和pop()是主要的接口函数。QStack继承了QVector,所以它拥有QVector的所有功能,同时提供了堆栈的特定操作。
(1)常用接口
-
构造函数:QStack() 创建一个空的QStack实例。
-
void push(const T &value):将元素value压入堆栈的顶部。
-
T pop():移除并返回堆栈顶部的元素。当堆栈为空时,调用此方法会导致未定义行为。
-
T &top():返回堆栈顶部的元素的引用。当堆栈为空时,调用此方法会导致未定义行为。
-
const T &top() const:返回堆栈顶部元素的const引用。当堆栈为空时,调用此方法会导致未定义行为。
-
bool isEmpty() const:如果堆栈为空,则返回true;否则返回false。
-
int size() const:返回堆栈中元素的数量。
-
void clear():清空堆栈,移除所有元素。
-
QStack<T> &operator+=(const T &value):将元素value压入堆栈的顶部,与push()方法功能相同。
-
QStack<T> &operator<<(const T &value):将元素value压入堆栈的顶部,与push()方法功能相同。
(2) QStack 示例
#include <QCoreApplication>
#include <QStack>
#include <QDebug>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 创建一个空的QStack实例QStack<int> stack;// 使用push()压入元素stack.push(10);stack.push(20);stack.push(30);// 使用top()查看栈顶元素qDebug() << "Top element:" << stack.top(); // 输出:Top element: 30// 使用size()查看堆栈大小qDebug() << "Stack size:" << stack.size(); // 输出:Stack size: 3// 使用pop()移除并返回栈顶元素int poppedValue = stack.pop();qDebug() << "Popped value:" << poppedValue; // 输出:Popped value: 30// 使用isEmpty()检查堆栈是否为空qDebug() << "Stack is empty:" << (stack.isEmpty() ? "Yes" : "No"); // 输出:Stack is empty: No// 使用operator<<压入元素stack << 40 << 50;// 使用clear()清空堆栈stack.clear();qDebug() << "Stack is empty after clear():" << (stack.isEmpty() ? "Yes" : "No"); // 输出:Stack is empty after clear(): Yesreturn a.exec();
}
2.5 QQueue
QQueue<T>是提供类似于队列先入先出(FIFO)操作的容器类。这种特性使得队列在处理一些需要按顺序执行任务的场景中表现出优越性。QQueue继承自QList,因此可以方便地利用QList的功能实现队列的基本操作。
(1)重要特性
-
任务调度:在操作系统或多线程应用中,QQueue可用于实现任务调度器,确保任务按照预定的顺序执行,避免资源竞争和死锁问题。
-
消息队列:在分布式系统或网络应用中,QQueue可以作为消息队列用于缓存和传输消息,确保消息的有序到达和处理。
-
数据缓冲:在数据处理和传输过程中,QQueue可以作为缓冲区,允许数据在生产者和消费者之间异步传输,提高系统的吞吐量和响应速度。
-
事件处理:在GUI应用程序中,QQueue可以用于实现事件队列,确保用户界面按顺序响应用户的操作。
(2)常用接口
-
QQueue():构造函数,创建一个空的队列。
-
~QQueue():析构函数,销毁队列及其所有元素。
-
void enqueue(const T &value):将值value添加到队列的末尾。
-
T dequeue():从队列的头部移除并返回第一个元素。如果队列为空,这个函数的行为是未定义的。
-
T &head():返回队列头部元素的引用。如果队列为空,这个函数的行为是未定义的。
-
const T &head() const:返回队列头部元素的只读引用。如果队列为空,这个函数的行为是未定义的。
-
bool isEmpty() const:返回队列是否为空的布尔值。
-
int size() const:返回队列中的元素个数。
-
void clear():清空队列中的所有元素。
-
bool contains(const T &value) const:检查队列是否包含特定值value。
-
int count(const T &value) const:返回队列中特定值value的个数。
-
T &first():返回队列中第一个元素的引用。如果队列为空,这个函数的行为是未定义的。
-
const T &first() const:返回队列中第一个元素的只读引用。如果队列为空,这个函数的行为是未定义的。
-
T &last():返回队列中最后一个元素的引用。如果队列为空,这个函数的行为是未定义的。
-
const T &last() const:返回队列中最后一个元素的只读引用。如果队列为空,这个函数的行为是未定义的。
(3)QQueue示例
#include <QCoreApplication>
#include <QQueue>
#include <QDebug>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 1. 创建一个空的QQueue对象QQueue<int> queue;// 2. 入队元素queue.enqueue(10);queue.enqueue(20);queue.enqueue(30);// 3. 获取队列大小qDebug() << "Queue size:" << queue.size(); // 输出:Queue size: 3// 4. 检查队列是否为空qDebug() << "Queue is empty:" << queue.isEmpty(); // 输出:Queue is empty: false// 5. 查看队列的头部元素qDebug() << "Queue head:" << queue.head(); // 输出:Queue head: 10// 6. 出队元素int firstElement = queue.dequeue();qDebug() << "Dequeued element:" << firstElement; // 输出:Dequeued element: 10// 7. 获取队列中的第一个和最后一个元素qDebug() << "First element:" << queue.first(); // 输出:First element: 20qDebug() << "Last element:" << queue.last(); // 输出:Last element: 30// 8. 检查队列是否包含特定值qDebug() << "Queue contains 20:" << queue.contains(20); // 输出:Queue contains 20: true// 9. 计算队列中特定值的个数qDebug() << "Count of 20 in queue:" << queue.count(20); // 输出:Count of 20 in queue: 1// 10. 清空队列queue.clear();qDebug() << "Queue size after clear:" << queue.size(); // 输出:Queue size after clear: 0return a.exec();
}
3.关联容器类
3.1 QSet
QSet是基于散列表的集合模板类,它存储数据的顺序是不定的,查找值的速度非常快。QSet<T>内部就是用QHash实现的。
QSet的重要性在于其高性能特性,这使得它成为处理大量数据时的理想选择。例如,在进行文本分析时,我们可能需要追踪大量独特的单词,QSet可以用于此类任务,以便快速检索和添加新单词。同样,QSet在编译器优化、数据库查询优化和网络应用中也发挥着关键作用。
(1)常用接口
构造函数和析构函数:
-
QSet():创建一个空的 QSet。
-
QSet(const QSet<T> &other):拷贝构造函数,用于创建一个与 other 相同的 QSet。
-
~QSet():析构函数,用于释放 QSet 占用的内存。
添加元素:
void insert(const T &value):将值插入 QSet。如果值已存在,不会插入重复值。
删除元素:
-
int remove(const T &value):删除 QSet 中等于 value 的元素,返回删除的元素个数(0 或 1)。
-
void clear():删除 QSet 中的所有元素。
查询元素:
-
bool contains(const T &value) const:检查 QSet 是否包含与 value 相等的元素,如果包含返回 true,否则返回 false。
-
int count(const T &value) const:返回 QSet 中与 value 相等的元素个数。
-
int size() const:返回 QSet 中的元素个数。
遍历元素:
-
QSetIterator<T> begin() const:返回指向 QSet 中第一个元素的迭代器。
-
QSetIterator<T> end() const:返回指向 QSet 中最后一个元素之后位置的迭代器。
操作符重载:
-
QSet<T> &operator+=(const T &value):将 value 添加到 QSet 中,如果已存在则不添加,返回 *this。
-
QSet<T> &operator-=(const T &value):从 QSet 中移除与 value 相等的元素,返回 *this。
-
QSet<T> &operator|=(const QSet<T> &other):将 other 中的所有元素添加到 QSet 中,返回 *this。
-
QSet<T> &operator&=(const QSet<T> &other):保留 QSet 中与 other 的交集元素,返回 *this。
-
QSet<T> &operator^=(const QSet<T> &other):将 QSet 中与 other 不相交的元素进行合并,返回 *this。
集合操作:
-
QSet<T> unite(const QSet<T> &other) const:返回 QSet 与 other 的并集。
-
QSet<T> intersect(const QSet<T> &other) const:返回 QSet 与 other 的交集。
-
QSet<T> subtract(const QSet<T> &other) const:返回 QSet 与 other 的差集。
-
QSet<T> symmetricDifference(const QSet<T> &other) const:返回 QSet 与 other 的对称差集(只存在于一个集合中的元素)。
注意:QSet 的元素类型 T 必须提供 qHash(const T &) 函数以及重载 operator== 以支持元素的比较和哈希。
(2)QSet示例
#include <QSet>
#include <QString>
#include <QDebug>int main() {// 创建空 QSetQSet<QString> set;// 添加元素set.insert("apple");set.insert("banana");set.insert("orange");// 检查元素是否包含在 QSet 中if (set.contains("banana")) {qDebug() << "Set contains banana";}// QSet 中的元素个数qDebug() << "Size of set:" << set.size();// 遍历 QSet 中的元素for (const QString &value : set) {qDebug() << value;}// 删除元素set.remove("apple");// 检查 QSet 是否包含已删除的元素if (!set.contains("apple")) {qDebug() << "Apple has been removed from the set";}// 使用操作符重载QSet<QString> set2;set2.insert("cherry");set2.insert("banana");QSet<QString> unitedSet = set | set2; // 并集QSet<QString> intersectedSet = set & set2; // 交集QSet<QString> differenceSet = set - set2; // 差集QSet<QString> symmetricDiffSet = set ^ set2; // 对称差集qDebug() << "United set:" << unitedSet;qDebug() << "Intersected set:" << intersectedSet;qDebug() << "Difference set:" << differenceSet;qDebug() << "Symmetric difference set:" << symmetricDiffSet;// 清空 QSetset.clear();qDebug() << "Size of set after clearing:" << set.size();return 0;
}
3.2 QMap
QMap<Key,T>提供一个字典(关联数组),一个键映射到一个值。QMap内部使用平衡二叉树(红黑树)作为底层数据结构,提供了高效的插入、删除和查找操作。QMap存储数据是按照键的顺序,如果不在乎存储顺序,使用QHash会更快。
(1)应用场景
-
字典和映射:QMap可以用作字典或映射,将一组键与相应的值相关联。这可以用于存储和检索配置设置、用户数据、缓存等。
-
排序数据:QMap内部按照键的顺序对数据进行排序。这使得QMap在需要对数据进行排序的场景下非常合适。插入新数据时,QMap会自动将其插入到正确的位置。
-
索引和计数:QMap可以用于对数据进行索引和计数。例如,统计文本中每个单词出现的次数或将项目ID映射到项目详细信息。
-
数据分组和聚合:QMap可以用于对数据进行分组和聚合。例如,将订单数据按照客户进行分组或将学生按照班级进行分组。
-
配置和属性存储:QMap可以用于存储配置数据或对象的属性。例如,将设置名称映射到设置值或将对象ID映射到对象属性。
(2)常用接口
-
insert(key, value):向QMap中插入一个键值对。如果已存在具有相同键的条目,则用新值替换旧值。
-
remove(key):从QMap中删除与给定键关联的条目。
-
erase(key):从QMap中删除与给定键关联的条目。
-
contains(key):检查QMap是否包含与给定键关联的条目。
-
value(key):返回与给定键关联的值。如果找不到键,则返回默认构造的值。
-
keys():返回QMap中所有键的列表。
-
values():返回QMap中所有值的列表。
-
size():返回QMap中的条目数。
-
isEmpty():检查QMap是否为空。
-
clear():清空QMap中的所有条目。
(3)QMap示例
#include <QCoreApplication>
#include <QMap>
#include <QString>
#include <QDebug>int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 创建QMap并插入键值对QMap<QString, int> map;map.insert("one", 1);map.insert("two", 2);map.insert("three", 3);qDebug() << "Initial QMap: " << map;// 检查QMap是否包含某个键if (map.contains("two")) {qDebug() << "QMap contains key 'two'";}// 获取键对应的值int value = map.value("two");qDebug() << "Value for key 'two': " << value;//在使用value()函数查找键值时,还可以指定一个缺省的返回值,示例如下:map.value("four",4);//这表示如果在map里找到键“four”,就返回关联的值,否则返回值为4。// 获取所有键和值QList<QString> keys = map.keys();QList<int> values = map.values();qDebug() << "Keys: " << keys;qDebug() << "Values: " << values;// 获取QMap大小int size = map.size();qDebug() << "Size of QMap: " << size;// 删除键值对map.remove("two");qDebug() << "QMap after removing key 'two': " << map;// 使用迭代器遍历QMapqDebug() << "Iterating through QMap:";QMap<QString, int>::const_iterator i;for (i = map.constBegin(); i != map.constEnd(); ++i) {qDebug() << i.key() << ": " << i.value();}// 清空QMapmap.clear();qDebug() << "QMap after clearing: " << map;return a.exec();
}
3.3 QMultiMap
QMultiMap是QMap的子类,是用于处理多值映射的便利类。多值映射就是一个键可以对应多个值。这种数据结构典型的用例包括但不限于:管理分组的数据、实现多值字典、存储键值对数据等。QMap正常情况下不允许多值映射,除非使用QMap::insertMulti()添加键值对。QMultiMap是QMap的子类,所以QMap的大多数函数在QMultiMap都是可用的,但是有几个特殊的,QMultiMap::insert()等效于QMap::insertMulti(),QMultiMap::replace()等效于QMap::insert()。
(1)常用接口
插入和删除:
-
insert:向 QMultiMap 中插入一个键值对。如果已经存在具有相同键的键值对,则新的键值对将被添加到已有键值对之后。
-
insertMulti:类似于 insert,但返回指向新插入键值对的迭代器。
-
remove:从 QMultiMap 中删除与指定键和值匹配的所有键值对。返回被删除键值对的数量。
-
clear:清除 QMultiMap 中的所有键值对。
查找:
-
value:返回与指定键关联的第一个值。如果找不到匹配的键,则返回默认值。
-
values:返回与指定键关联的所有值的列表。
-
count:返回与指定键关联的值的数量。
-
find:返回指向与指定键关联的第一个值的迭代器。如果找不到匹配的键,则返回 end()。
-
begin、end:返回指向 QMultiMap 开始或结束位置的迭代器。
-
erase:删除指定位置的键值对,并返回指向下一个键值对的迭代器。
大小和容量:
-
isEmpty:判断 QMultiMap 是否为空。
-
size、count:返回 QMultiMap 中的键值对数量。
键和值:
-
keys:返回 QMultiMap 中所有键的列表。可以通过传入一个值参数来获得与指定值关联的所有键。
-
values:返回 QMultiMap 中所有值的列表。
-
unite:将另一个 QMultiMap 的键值对添加到当前 QMultiMap 中。如果两个 QMultiMap 中具有相同的键,则将值合并到一个键下。
比较操作:
-
operator==、operator!=:比较两个 QMultiMap 是否相等或不等。
STL 风格迭代器:
-
QMultiMap 提供了类似 STL 的迭代器接口,如 begin、end、constBegin、constEnd 等,使得用户可以方便地遍历和操作键值对。
(2)QMultiMap示例
#include <QCoreApplication>
#include <QMultiMap>
#include <QDebug>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 1. 创建一个空的 QMultiMap 对象QMultiMap<QString, int> ageMap;// 2. 使用 insert 插入键值对ageMap.insert("Alice", 25);ageMap.insert("Bob", 30);ageMap.insert("Charlie", 22);ageMap.insert("Bob", 35); // 允许有相同的键// 3. 使用 insertMulti 插入键值对ageMap.insertMulti("Alice", 26);// 4. 遍历 QMultiMapfor (auto it = ageMap.begin(); it != ageMap.end(); ++it) {qDebug() << it.key() << ": " << it.value();}// 5. 使用 value 获取第一个匹配的值qDebug() << "First value for Alice: " << ageMap.value("Alice");// 6. 使用 values 获取所有匹配的值QList<int> aliceAges = ageMap.values("Alice");qDebug() << "All values for Alice: " << aliceAges;// 7. 使用 count 获取键的数量qDebug() << "Count for Alice: " << ageMap.count("Alice");// 8. 使用 find 获取匹配键的迭代器auto it = ageMap.find("Bob");if (it != ageMap.end()) {qDebug() << "Found Bob: " << it.value();}// 9. 使用 erase 删除一个键值对ageMap.erase(ageMap.find("Charlie"));// 10. 使用 remove 删除所有匹配的键值对ageMap.remove("Alice");// 11. 检查 QMultiMap 是否为空qDebug() << "Is empty: " << ageMap.isEmpty();// 12. 获取 QMultiMap 的大小qDebug() << "Size: " << ageMap.size();// 13. 获取所有键和值qDebug() << "Keys: " << ageMap.keys();qDebug() << "Values: " << ageMap.values();// 14. 使用 unite 合并两个 QMultiMapQMultiMap<QString, int> anotherAgeMap;anotherAgeMap.insert("Diana", 28);ageMap.unite(anotherAgeMap);qDebug() << "After unite: " << ageMap;// 15. 清空 QMultiMapageMap.clear();qDebug() << "Size after clear: " << ageMap.size();return a.exec();
}
3.4 QHash
QHash是基于散列表来实现字典功能的模板类,QHash<Key,T>存储的键值对具有非常快的
查找速度。
QHash与QMap的功能和用法相似,区别在于以下几点:
-
QHash比QMap的查找速度快;
-
在QMap上遍历时,数据项是按照键排序的,而QHash的数据项是任意顺序的;
-
QMap的键必须提供“<”运算符,QHash的键必须提供“一”运算符和一个名称为qHash()
的全局散列函数。
(1)常用接口
插入: QMap 支持多种插入方法,例如:
-
insert():插入一个键值对,如果已存在相同的键,则值将被替换。
-
insertMulti():插入一个键值对,即使存在相同的键,值也会被保留。
QMap<QString, int> map;
map.insert("apple", 1);
map.insert("banana", 2);
map.insertMulti("apple", 3);
自定义哈希函数: QHash 允许你为自定义类型提供哈希函数。你需要为你的类型实现一个名为 qHash 的全局函数,该函数接受你的类型作为参数并返回一个 uint 值。
uint qHash(const CustomType &key, uint seed = 0) noexcept;
自定义比较函数: QHash 默认使用 operator== 进行键值比较。如果你需要使用自定义比较函数,可以使用 QHash 的一个变体——QHashF,它接受一个自定义的比较函数对象。
QHash<Key, Value, KeyEqual> hash;
容量管理: QHash 允许你控制其底层哈希表的大小。使用 reserve() 函数预分配空间可以避免不必要的重新哈希。此外,capacity() 函数可以获取当前的容量,squeeze() 函数可以收缩容量以适应当前的元素数量。
hash.reserve(100);
int cap = hash.capacity();
hash.squeeze();
QMultiHash: QHash 不允许多个键关联到同一个值。QMultiHash 允许这种关联,支持添加和查找具有相同键的值。
QMultiHash<QString, int> multiHash;
multiHash.insert("key", 1);
multiHash.insert("key", 2);
QList<int> values = multiHash.values("key");
遍历: QHash 提供了多种遍历方式。可以使用 C++11 范围迭代(range-for loop)遍历 QHash,也可以使用迭代器(iterator)进行遍历。
for (const auto &key : hash.keys()) { ... }
for (const auto &value : hash.values()) { ... }
for (auto it = hash.begin(); it != hash.end(); ++it) { ... }
其他操作: QHash 提供了一些其他有用的操作,如交换(swap)、取差集(subtract)、合并(unite)等。
QHash<QString, int> hash1, hash2;
hash1.swap(hash2);
hash1.subtract(hash2);
hash1.unite(hash2);
(2)QHash示例
#include <QHash>
#include <QString>
#include <QDebug>// 自定义哈希函数,这里我们使用 Qt 提供的 qHash() 函数作为示例
uint qHash(const int &key, uint seed = 0) {return qHash(key, seed);
}// 自定义键相等操作,这里直接使用整数的相等操作
bool operator==(const int &key1, const int &key2) {return key1 == key2;
}int main() {// 1. 构造一个空的 QHashQHash<int, QString> hash;// 2. 插入键值对hash.insert(1, "one");hash.insert(2, "two");hash.insert(3, "three");// 3. 访问元素qDebug() << "Value for key 1:" << hash[1]; // 输出 "one"// 4. 修改元素hash[1] = "ONE";qDebug() << "Modified value for key 1:" << hash[1]; // 输出 "ONE"// 5. 检查元素是否存在if (hash.contains(3)) {qDebug() << "Key 3 is in the hash.";}// 6. 删除元素hash.remove(2);// 7. 获取键和值列表QList<int> keys = hash.keys();QList<QString> values = hash.values();// 8. 迭代 QHashQHash<int, QString>::iterator it;for (it = hash.begin(); it != hash.end(); ++it) {qDebug() << "Key:" << it.key() << "Value:" << it.value();}// 9. 从 QHash 提取一个值并删除该键值对QString value = hash.take(3);qDebug() << "Taken value for key 3:" << value; // 输出 "three"// 10. 检查 QHash 是否为空if (hash.isEmpty()) {qDebug() << "Hash is empty.";}// 11. 获取 QHash 的大小int size = hash.size();qDebug() << "Hash size:" << size; // 输出 2// 12. 清空 QHashhash.clear();if (hash.isEmpty()) {qDebug() << "Hash is now empty.";}// 13. 隐式共享QHash<int, QString> hash2;hash2 = hash; // hash 和 hash2 现在共享同一份数据if (hash.isSharedWith(hash2)) {qDebug() << "hash and hash2 are shared.";}return 0;
}
3.5 QMuItiHash
QMultiHash是QHash的子类,是用于处理多值映射的便利类,其用法与QMultiMap类似。与其它容器类(如QHash)相比,QMultiHash提供了一些额外的功能,如:
-
容易处理具有相同键的数据:QMultiHash能够在一个键下存储多个值,使得管理这类数据变得简单高效。
-
高性能:QMultiHash基于哈希表实现,因此查找、插入和删除操作的平均时间复杂度为O(1)。这意味着它在处理大量数据时仍然具有高性能。
-
灵活的迭代器:QMultiHash提供了多种迭代器,例如const_iterator、iterator等,方便您遍历和操作容器中的数据。
-
容易扩展和集成:QMultiHash作为Qt框架的一部分,与其他Qt类和功能有很好的兼容性。此外,QMultiHash的源代码可供查阅和修改,便于根据需求进行定制。
QMultiHash示例:
#include <QMultiHash>
#include <QList>
#include <QDebug>int main() {// 1. 创建一个 QMultiHashQMultiHash<QString, int> multiHash;// 2. 添加元素multiHash.insert("Alice", 25);multiHash.insert("Bob", 30);multiHash.insert("Alice", 28);multiHash.insert("Charlie", 23);// 3. 获取键值对数量qDebug() << "The multiHash has" << multiHash.count() << "key-value pairs.";// 4. 检查是否包含某个键if (multiHash.contains("Alice")) {qDebug() << "The multiHash contains the key 'Alice'.";}// 5. 获取某个键的值QList<int> aliceAges = multiHash.values("Alice");qDebug() << "Alice's ages are:" << aliceAges;// 6. 移除某个键值对multiHash.remove("Alice", 25);qDebug() << "After removing Alice's age 25, the multiHash contains" << multiHash.count() << "key-value pairs.";// 7. 使用迭代器遍历 QMultiHashqDebug() << "The multiHash contains the following key-value pairs:";for (auto it = multiHash.begin(); it != multiHash.end(); ++it) {qDebug() << it.key() << ":" << it.value();}// 8. 使用 C++11 范围遍历qDebug() << "The multiHash contains the following key-value pairs (using C++11 range-based loop):";for (const auto &pair : multiHash) {qDebug() << pair.first << ":" << pair.second;}// 9. 使用 uniqueKeys 获取去重后的键列表qDebug() << "The unique keys in the multiHash are:" << multiHash.uniqueKeys();// 10. 使用 keys 获取包含重复的键列表qDebug() << "All the keys in the multiHash are:" << multiHash.keys();// 11. 清空 QMultiHashmultiHash.clear();qDebug() << "After clearing, the multiHash has" << multiHash.count() << "key-value pairs.";return 0;
}