Qt 提供了丰富的容器类,这些容器类主要用于存储和管理数据,按照其内部组织结构和功能特性,大致可分为顺序容器和关联容器两大类:
顺序容器:
关联容器:
6. QMap - 键值对映射容器,键值对按键自动排序。
7. QHash - 哈希表实现的键值对容器,提供常数时间复杂度的快速查找能力。
8. QSet - 集合容器,只包含唯一元素,不存储值对应的键。
另外还有一些特殊用途的容器:
9. QStringList - 字符串列表容器,实际上是QList
的便捷版本,专用于存储字符串列表。
10. QByteArray - 字节数组容器,用于存储二进制数据。
以上容器类都是模板类,可以根据需要存储任何兼容类型的对象,并且它们在设计上力求简化接口、提高跨平台兼容性和线程安全性。相较于C++标准模板库(STL),Qt的容器类通常被认为更适合于GUI开发环境,尤其是考虑到多线程同步问题时。
QList详细介绍
QList是Qt框架中的一个重要的泛型容器类,它是动态数组的实现,但是它的内部实现并不是简单的连续内存区域,而是根据元素大小和数量选择最优的存储策略(可能是数组或者链表)。这意味着QList能够灵活地应对不同场景下的需求,尤其是在元素较小或者大量元素已预先分配空间的情况下,它会尽可能地利用连续内存来加速随机访问。
特点与功能
append()
、prepend()
、insert()
、removeAt()
、takeAt()
、replace()
等。优缺点
使用示例(增删改查)
#include
#include
// 创建一个存储整数的QList
QList numbers;
// 增加元素
numbers.append(1);
numbers.append(2);
numbers.append(3);
qDebug() << "After appending: " << numbers; // 输出: [1, 2, 3]
// 修改元素
numbers[1] = 10;
qDebug() << "After modifying: " << numbers; // 输出: [1, 10, 3]
// 查询元素
if (numbers.contains(10)) {
qDebug() << "10 is in the list.";
}
// 删除元素
numbers.removeOne(10); // 删除第一个出现的10
qDebug() << "After removing 10: " << numbers; // 输出: [1, 3]
// 查找并替换元素
int index = numbers.indexOf(3);
if (index != -1) {
numbers.replace(index, 20); // 将索引处的3替换为20
}
qDebug() << "After replacing: " << numbers; // 输出: [1, 20]
// 在特定位置插入元素
numbers.insert(1, 5);
qDebug() << "After inserting at index 1: " << numbers; // 输出: [1, 5, 20]
以上代码片段演示了如何使用QList进行基本的增删改查操作。同时,还可以使用takeAt()
方法移除并返回指定索引的元素,以及其他更多的高级功能,如反转列表、合并两个列表等。
QVector 详细介绍
QVector 是 Qt 框架中的一个模板类,类似于 C++ STL 中的 std::vector
,它提供了一个动态可变大小的数组,允许高效地存储和操作相同类型的数据。QVector 主要用于需要随机访问和连续存储空间的场景,它的内部实现是一个可动态扩展的连续内存区域。
优点:
缺点:
使用示例及增删改查功能演示:
#include
#include
int main() {
// 创建一个空的 QVector
QVector numbers;
// 添加元素(增):
numbers.append(10);
numbers.append(20);
numbers.append(30);
// 插入元素(增):
numbers.insert(1, 15); // 在索引1处插入15
qDebug() << "After insertion:" << numbers; // 输出:[10, 15, 20, 30]
// 修改元素(改):
numbers[1] = 16;
qDebug() << "After modification:" << numbers; // 输出:[10, 16, 20, 30]
// 查找元素:
if (numbers.contains(16)) {
qDebug() << "16 is in the vector.";
}
// 删除最后一个元素
numbers.pop_back();
// 获取第一个元素
int first = numbers.first();
// 获取最后一个元素
int last = numbers.last();
// 删除元素(删):
numbers.removeAt(1);
qDebug() << "After removal of index 1:" << numbers; // 输出:[10, 20, 30]
// 清除所有元素:
numbers.clear();
qDebug() << "After clear:" << numbers; // 输出:[]
return 0;
}
总结:
QVector 非常适用于那些需要高效随机访问、不需要频繁插入删除操作的情况,尤其是当你预见到数据集大小可能变动但总体上保持相对稳定时。如果你的应用场景涉及到大量动态插入和删除操作,尤其是在容器中间位置,那么可能需要考虑使用 QList 或其他更适合的数据结构。
QLinkedList 详细介绍
QLinkedList 是 Qt 框架中的一个模板类,它实现了双向链表数据结构,类似于 C++ STL 中的 std::list
。QLinkedList 适用于频繁执行插入和删除操作,特别是在列表中间位置,而不依赖于高效的随机访问。
优点:
缺点:
使用示例及增删改查功能演示:
#include
#include
int main() {
// 创建一个空的 QLinkedList
QLinkedList numbers;
// 添加元素(增):
numbers.append(10);
numbers.append(20);
numbers.append(30);
// 插入元素(增):
numbers.insertBefore(numbers.begin(), 5); // 在开头插入5
qDebug() << "After insertion:" << numbers; // 输出:[5, 10, 20, 30]
// 修改元素(改):
auto it = numbers.begin(); // 获取第一个元素的迭代器
++it; // 移动到第二个元素
*it = 15; // 修改第二个元素的值
qDebug() << "After modification:" << numbers; // 输出:[5, 15, 20, 30]
// 查找并修改元素:
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
if (*it == 20) {
*it = 25;
break;
}
}
qDebug() << "After searching and modifying:" << numbers; // 输出:[5, 15, 25, 30]
// 删除元素(删):
it = numbers.begin(); // 获取第一个元素迭代器
++it; // 移动到要删除的元素
numbers.erase(it); // 删除第二个元素
qDebug() << "After removal:" << numbers; // 输出:[5, 25, 30]
// 清空链表:
numbers.clear();
qDebug() << "After clear:" << numbers; // 输出:[]
return 0;
}
总结:
QLinkedList 在插入和删除操作频繁,尤其当列表顺序经常改变的场合表现优秀。如果你的应用程序要求高效地在列表任意位置插入或删除数据,并且不十分依赖于随机访问的速度,QLinkedList 就是一个理想的选择。但对于需要快速随机访问或者对内存占用有严格限制的场景,则应考虑使用 QVector 等连续存储的数据结构。
QStack 详细介绍
QStack 是 Qt 框架提供的一个模板类,它实现了栈(Stack)这一数据结构,遵循后进先出(Last In, First Out, LIFO)原则。栈在编程中非常常见,主要用于那些需要“最后加入的元素最先取出”的逻辑场景。
优点:
push()
(入栈)、pop()
(出栈)和 top()
(查看栈顶元素),易于理解和使用。缺点:
使用示例及增删改查功能演示:
#include
#include
int main() {
// 创建一个空的 QStack
QStack stack;
// 增加元素(入栈)
stack.push(10);
stack.push(20);
stack.push(30);
qDebug() << "After pushing elements:" << stack; // 输出可能是 "[30, 20, 10]",实际输出顺序取决于 Qt 库的实现
// 查看栈顶元素(读取)
int topElement = stack.top();
qDebug() << "Top element is:" << topElement; // 输出:30
// 删除并返回栈顶元素(出栈)
int poppedElement = stack.pop();
qDebug() << "Popped element is:" << poppedElement; // 输出:30
qDebug() << "After popping an element:" << stack; // 输出可能是 "[20, 10]"
// 注意:QStack 不支持在栈中直接修改元素,若需修改栈顶元素,需先 pop 再 push 修改后的值
// 清空栈
stack.clear();
qDebug() << "After clearing the stack:" << stack; // 输出:""
return 0;
}
// 注意:虽然 QStack 继承自 QVector 或 QList 的信息存在一些矛盾,实际上 QStack 的继承关系可能随 Qt 版本不同有所变化,
// 在某些版本中它继承自 QVector,而在另一些版本中可能继承自 QList,但无论如何,它都保留了栈的核心操作。
总结:QStack 主要用于简化堆栈操作,适用于需要快速存取和按先进后出顺序处理数据的场景。不过,由于其设计目的单一,对于需要复杂查询或排序需求的数据处理来说不太适用。另外,关于 QStack 继承自哪个基类,建议查阅最新的 Qt 文档以获得准确信息。
QQueue 详细介绍
QQueue 是 Qt 框架中的一个模板类,它实现了队列(Queue)数据结构,遵循先进先出(First In, First Out, FIFO)的原则。队列是一个线性表,新添加的元素会被放在队列的末尾(称为enqueue),而从队列中移除或读取元素则会从队列的前端开始(称为dequeue)。
优点:
enqueue()
(入队)和 dequeue()
(出队)以及 head()
(查看队首元素)等。size()
(获取队列长度)、clear()
(清空队列)等,也可以使用迭代器进行遍历。缺点:
使用示例及增删改查功能演示:
#include
#include
int main() {
// 创建一个空的 QQueue
QQueue numbersQueue;
// 增加元素(入队)
numbersQueue.enqueue(10);
numbersQueue.enqueue(20);
numbersQueue.enqueue(30);
qDebug() << "After enqueueing elements:" << numbersQueue;
// 查看队首元素(读取,但不移除)
int frontElement = numbersQueue.head();
qDebug() << "Front element is:" << frontElement;
// 删除并返回队首元素(出队)
int dequeuedElement = numbersQueue.dequeue();
qDebug() << "Dequeued element is:" << dequeuedElement;
qDebug() << "After dequeueing an element:" << numbersQueue;
// 修改队列中的元素(由于队列只允许在队尾插入,此处假设我们先出队再重新入队修改后的值)
numbersQueue.dequeue();
numbersQueue.enqueue(frontElement + 1); // 修改原队首元素的值
qDebug() << "After modifying an element by re-enqueuing:" << numbersQueue;
// 清空队列
numbersQueue.clear();
qDebug() << "After clearing the queue:" << numbersQueue;
return 0;
}
注意:QQueue 一般不提倡直接修改队列中的元素,因为它设计的目的在于线性、顺序的数据处理。如确实需要修改队列中的某元素,一般需要先出队再入队修改后的值。
总结:QQueue 适用于那些需要按顺序处理任务、消息传递或者其他先进先出逻辑的场景。它在单线程环境中表现良好,但在多线程环境时需要谨慎处理并发访问问题。由于其基于QList的设计,对尾部的增删操作非常高效,而对于非队首元素的操作则应避免。
QMap 详细介绍
QMap 是 Qt 框架中的一种关联容器模板类,它实现了关联数组或字典的功能,允许通过键(Key)来存储和检索对应的值(Value)。QMap 中的键值对是按照键的升序排列的,这是它与标准库中 std::map
的主要区别之一。
优点:
<
),这使得可以通过键的顺序遍历整个映射。缺点:
<
,这在自定义类型作为键时需要用户自行定义。使用示例及增删改查功能演示:
#include
#include
int main() {
// 创建一个空的 QMap
QMap studentGrades;
// 插入元素(增)
studentGrades.insert("Alice", 85);
studentGrades.insert("Bob", 90);
studentGrades.insert("Charlie", 88);
qDebug() << "After inserting:" << studentGrades; // 输出键值对的集合
// 修改元素(改)
if (studentGrades.contains("Alice")) {
studentGrades["Alice"] = 92; // 直接通过键修改值
}
qDebug() << "After modification:" << studentGrades;
// 查找元素
bool hasGrade = studentGrades.contains("Alice"); // 检查是否存在键
int aliceGrade = studentGrades.value("Alice", -1); // 获取值,如果没有该键则返回默认值
qDebug() << "Does 'Alice' have a grade? " << hasGrade;
qDebug() << "Grade of Alice: " << aliceGrade;
// 删除元素(删)
studentGrades.remove("Bob");
qDebug() << "After removal of 'Bob':" << studentGrades;
// 迭代遍历
foreach (const QString &name, studentGrades.keys()) {
int grade = studentGrades.value(name);
qDebug() << name << "has grade:" << grade;
}
return 0;
}
总结:
QMap 是一种适用于有序键值对存储的理想选择,特别是当应用程序需要按键的自然顺序遍历时。然而,如果对查找效率有极高要求且不在乎元素的顺序,或者需要频繁插入和删除元素,QHash 可能是更好的选择。QMap 能够有效处理各种复杂的键值存储需求,并且因其有序性而增强了代码的可读性和易用性。
QHash 是 Qt 框架中的一个容器类,用于存储键值对。
优点:
缺点:
使用示例:
#include
#include
int main() {
// 创建 QHash 对象
QHash hash;
// 插入键值对
hash["name"] = 10;
hash["age"] = 20;
hash["gender"] = 30;
// 查找键对应的值
int value = hash["name"];
qDebug() << "Value for 'name' : " << value;
// 删除键值对
hash.remove("age");
// 修改键对应的值
hash["gender"] = 40;
// 检查键是否存在
if (hash.contains("name")) {
qDebug() << "Key 'name' exists.";
} else {
qDebug() << "Key 'name' does not exist.";
}
return 0;
}
在上述示例中,演示了 QHash 的增删改查功能:
hash["key"] = value;
插入键值对。hash.remove("key");
删除键值对。hash.contains("key");
检查键是否存在,使用 hash["key"];
获取键对应的值。QSet 是 Qt 框架中的一个集合类,用于存储唯一元素。
优点:
缺点:
使用示例:
#include
#include
int main() {
// 创建 QSet 对象
QSet set;
// 增加元素
set << 1 << 2 << 3 << 4 << 5;
// 检查元素是否存在
if (set.contains(3)) {
qDebug() << "Element 3 exists in the set.";
} else {
qDebug() << "Element 3 does not exist in the set.";
}
// 删除元素
set.remove(2);
// 修改(实际上是添加或删除)元素
set.insert(6);
// 遍历元素
for (int element : set) {
qDebug() << element;
}
return 0;
}
在上述示例中,演示了 QSet 的增删改查功能:
<<
操作符或 insert()
函数添加元素。remove()
函数删除元素。contains()
函数检查元素是否存在,使用遍历方式查看所有元素。QStringList
是 Qt 框架中的一个字符串列表类,用于存储和操作一系列字符串。
优点:
缺点:
使用示例:
#include
#include
int main() {
QStringList list;
// 增加元素
list << "apple" << "banana" << "orange";
// 查询元素是否存在
if (list.contains("apple")) {
qDebug() << "Element 'apple' exists in the list.";
} else {
qDebug() << "Element 'apple' does not exist in the list.";
}
// 删除元素
list.removeAll("banana");
// 修改元素
list[0] = "new_apple";
// 遍历元素
for (const QString &str : list) {
qDebug() << str;
}
return 0;
}
在上述示例中,演示了 QStringList
的增删改查功能:
<<
操作符添加元素。removeAll()
函数删除元素。contains()
函数检查元素是否存在,使用遍历方式查看所有元素。在 Qt 中,QByteArray
类被广泛用于处理二进制数据、图像、音频、视频等多媒体数据,也可以用于网络传输和文件操作等场景。其主要特点如下:
QByteArray
的内部实现使用了指针和引用计数技术,可以高效地存储和访问大量数据。QByteArray
提供了丰富的字节数组操作函数,例如append
、insert
、replace
、remove
等,可以灵活地操作字节数组。QByteArray
支持多种编码方式,例如 ASCII、UTF-8、UTF-16 等,可以方便地处理不同编码的数据。下面给出一个简单例子,用于入门QByteArray
:
#include
#include
int main() {
// 定义一个空 QByteArray 对象
QByteArray qByteArray("");
// 在尾部添加字符串
qByteArray.append("daniel");
// 返回数据指针
qDebug() << "qByteArray = " << qByteArray.data() << "\n";
// 返回大小,不保护末尾的 '\n'
qDebug() << "The size of qByteArray is " << qByteArray.size() << "\n";
// 查询重复次数
qDebug() << "The number of occurrences of 'a' is " << qByteArray.count('a') << "\n";
// 更改填充值
qByteArray.fill('a');
// 返回数据指针
qDebug() << "qByteArray = " << qByteArray.data() << "\n";
return 0;
}
以上容器类都是模板类,可以根据需要存储任何兼容类型的对象,并且它们在设计上力求简化接口、提高跨平台兼容性和线程安全性。相较于C++标准模板库(STL),Qt的容器类通常被认为更适合于GUI开发环境,尤其是考虑到多线程同步问题时。