Qt6 常用数据结构详解
Qt6 提供了丰富的数据结构类,这些类在 Qt 应用程序开发中广泛使用。本文将详细介绍 Qt6 中常用的数据结构,包括它们的特性、用法和最佳实践。
一、容器类 (Containers)
Qt6 提供了一套模板化的容器类,类似于 STL,但专为 Qt 设计,具有更好的集成性和性能。
1.1 顺序容器 (Sequence Containers)
1.1.1 QList
QList
是 Qt 中最常用的顺序容器之一,适用于大多数情况下的列表操作。
#include <QList>
QList<QString> names;
names << "Alice" << "Bob" << "Charlie";
// 访问元素
QString first = names.first(); // "Alice"
QString last = names.last(); // "Charlie"
// 添加元素
names.append("David");
// 插入元素
names.insert(1, "Eve");
// 删除元素
names.removeAt(2); // 删除第三个元素
特点:
- 内部实现为数组或链表,取决于大小
- 随机访问效率高(O(1))
- 插入和删除效率取决于位置(头部 O(1),中间/尾部 O(n))
1.1.2 QVector
QVector
类似于 std::vector
,提供动态数组功能。
#include <QVector>
QVector<int> numbers;
numbers<< 1 << 2 << 3;
// 访问元素
int first = numbers.first(); // 1
int last = numbers.last(); // 3
// 添加元素
numbers.append(4);
// 插入元素
numbers.insert(1, 5);
// 删除元素
numbers.removeAt(2); // 删除第三个元素
特点:
- 连续内存存储
- 随机访问效率高(O(1))
- 插入和删除效率较低(O(n))
1.1.3 QLinkedList
QLinkedList
提供双向链表功能。
#include <QLinkedList>
QLinkedList<QString> names;
names << "Alice" << "Bob" << "Charlie";
// 访问元素(不如QList方便)
QString first = names.first(); // "Alice"
QString last = names.last(); // "Charlie"
// 添加元素
names.append("David");
// 插入元素
names.insert(names.begin() + 1, "Eve");
// 删除元素
names.removeOne("Bob");
特点:
- 插入和删除效率高(O(1))
- 随机访问效率低(O(n))
- 内存不连续
1.2 关联容器 (Associative Containers)
1.2.1 QMap
QMap
提供键值对存储,按键排序。
#include <QMap>
QMap<QString, int> ageMap;
ageMap["Alice"] = 25;
ageMap["Bob"] = 30;
ageMap["Charlie"] = 35;
// 访问元素
int aliceAge = ageMap["Alice"]; // 25
// 遍历
for (auto it = ageMap.begin(); it != ageMap.end(); ++it) {
qDebug() << it.key() << ":" << it.value();
}
// 查找
if (ageMap.contains("Bob")) {
qDebug() << "Found Bob";
}
特点:
- 键值对存储
- 自动按键排序
- 查找效率高(O(log n))
1.2.2 QHash
QHash
类似于 QMap
,但不保证顺序。
#include <QHash>
QHash<QString, int> ageHash;
ageHash["Alice"] = 25;
ageHash["Bob"] = 30;
ageHash["Charlie"] = 35;
// 访问元素
int aliceAge = ageHash["Alice"]; // 25
// 遍历
for (auto it = ageHash.begin(); it != ageHash.end(); ++it) {
qDebug() << it.key() << ":" << it.value();
}
// 查找
if (ageHash.contains("Bob")) {
qDebug() << "Found Bob";
}
特点:
- 键值对存储
- 不保证顺序
- 查找效率通常比
QMap
高(O(1) 平均情况)
1.2.3 QSet
QSet
提供唯一元素的集合。
#include <QSet>
QSet<QString> names;
names << "Alice" << "Bob" << "Charlie";
// 添加元素
names.insert("David");
// 删除元素
names.remove("Bob");
// 检查存在
if (names.contains("Alice")) {
qDebug() << "Found Alice";
}
// 遍历
for (const QString &name : names) {
qDebug() << name;
}
特点:
- 唯一元素集合
- 不保证顺序
- 查找效率高(O(1) 平均情况)
1.3 容器适配器
1.3.1 QStack
QStack
提供后进先出(LIFO)的栈结构。
#include <QStack>
QStack<int> stack;
stack.push(1);
stack.push(2);
stack.push(3);
// 访问栈顶元素
int top = stack.top(); // 3
// 弹出栈顶元素
stack.pop(); // 移除3
// 检查是否为空
if (stack.isEmpty()) {
qDebug() << "Stack is empty";
} else {
qDebug() << "Stack is not empty";
}
特点:
- 后进先出(LIFO)
- 基于
QVector
实现
1.3.2 QQueue
QQueue
提供先进先出(FIFO)的队列结构。
#include <QQueue>
QQueue<int> queue;
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
// 访问队首元素
int front = queue.head(); // 1
// 出队
queue.dequeue(); // 移除1
// 检查是否为空
if (queue.isEmpty()) {
qDebug() << "Queue is empty";
} else {
qDebug() << "Queue is not empty";
}
特点:
- 先进先出(FIFO)
- 基于
QList
实现
二、字符串类 (String Classes)
2.1 QString
QString
是 Qt 中处理 Unicode 字符串的主要类。
#include <QString>
QString str = "Hello, World!";
// 拼接字符串
str += " Welcome to Qt.";
// 子字符串
QString sub = str.mid(7, 5); // "World"
// 查找子字符串
int pos = str.indexOf("Qt"); // 13
// 替换
str.replace("Qt", "C++");
// 转换大小写
QString upper = str.toUpper(); // "HELLO, WORLD! WELCOME TO C++."
特点:
- Unicode 支持
- 高效的内存管理
- 丰富的字符串操作函数
2.2 QByteArray
QByteArray
用于处理原始字节数据。
#include <QByteArray>
QByteArray data = "Hello";
// 转换为十六进制
QString hex = data.toHex(); // "48656c6c6f"
// 追加数据
data.append(" World");
// 查找子字节序列
int pos = data.indexOf("World"); // 6
// 转换为整数
bool ok;
int num = data.left(3).toInt(&ok, 16); // 如果data是"1a2",则num=418
特点:
- 处理二进制数据
- 高效的内存管理
- 支持多种编码转换
三、日期和时间类 (Date and Time Classes)
3.1 QDate
QDate
表示公历日期。
#include <QDate>
QDate today = QDate::currentDate();
QDate specificDate(2023, 12, 25);
// 日期操作
QDate tomorrow = today.addDays(1);
QDate lastMonth = today.addMonths(-1);
// 格式化
QString formatted = today.toString("yyyy-MM-dd"); // "2023-11-15"
// 比较
if (today > specificDate) {
qDebug() << "Today is after Dec 25, 2023";
} else {
qDebug() << "Today is before or on Dec 25, 2023";
}
特点:
- 公历日期表示
- 丰富的日期操作函数
- 支持多种日期格式
3.2 QTime
QTime
表示时间(小时、分钟、秒、毫秒)。
#include <QTime>
QTime now = QTime::currentTime();
QTime specificTime(14, 30, 0); // 14:30:00
// 时间操作
QTime later = now.addSecs(3600); // 加1小时
QTime earlier = now.addSecs(-1800); // 减30分钟
// 格式化
QString formatted = now.toString("hh:mm:ss"); // "14:30:45"
// 比较
if (now > specificTime) {
qDebug() << "Current time is after 14:30:00";
} else {
qDebug() << "Current time is before or on 14:30:00";
}
特点:
- 时间表示(小时、分钟、秒、毫秒)
- 丰富的时间操作函数
- 支持多种时间格式
3.3 QDateTime
QDateTime
结合 QDate
和 QTime
表示日期和时间。
#include <QDateTime>
QDateTime now = QDateTime::currentDateTime();
QDateTime specificDateTime(QDate(2023, 12, 25), QTime(14, 30, 0));
// 日期时间操作
QDateTime later = now.addSecs(3600); // 加1小时
QDateTime earlier = now.addSecs(-1800); // 减30分钟
// 格式化
QString formatted = now.toString("yyyy-MM-dd hh:mm:ss"); // "2023-11-15 14:30:45"
// 比较
if (now > specificDateTime) {
qDebug() << "Current datetime is after Dec 25, 2023 14:30:00";
} else {
qDebug() << "Current datetime is before or on Dec 25, 2023 14:30:00";
}
特点:
- 结合日期和时间
- 丰富的日期时间操作函数
- 支持多种日期时间格式
四、文件和I/O类 (File and I/O Classes)
4.1 QFile
QFile
用于文件操作。
#include <QFile>
#include <QTextStream>
QFile file("example.txt");
if (file.open(QIODevice::ReadWrite | QIODevice::Text)) {
QTextStream in(&file);
QString content = in.readAll();
file.seek(0);
QTextStream out(&file);
out << "New content\n" << content;
file.close();
}
特点:
- 文件读写操作
- 支持多种打开模式
- 与
QTextStream
结合使用方便文本处理
4.2 QTextStream
QTextStream
用于文本流处理。
#include <QTextStream>
#include <QString>
QString data = "Hello, World!";
QTextStream out(stdout);
out << data << Qt::endl;
QFile file("output.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&file);
stream << "Writing to file\n";
file.close();
}
特点:
- 文本流处理
- 支持多种编码
- 方便的格式化输出
4.3 QDataStream
QDataStream
用于二进制数据流处理。
#include <QDataStream>
#include <QFile>
#include <QString>
QFile file("data.bin");
if (file.open(QIODevice::WriteOnly)) {
QDataStream out(&file);
out << QString("Hello") << 42 << 3.14;
file.close();
}
if (file.open(QIODevice::ReadOnly)) {
QDataStream in(&file);
QString str;
int num;
double pi;
in >> str >> num >> pi;
file.close();
qDebug() << str << num << pi; // "Hello" 42 3.14
}
特点:
- 二进制数据流处理
- 支持多种数据类型
- 方便的序列化和反序列化
五、容器类的使用技巧
5.1 选择合适的容器
- 顺序访问频繁:使用
QVector
或QList
- 键值对存储:使用
QMap
或QHash
- 唯一元素集合:使用
QSet
- 栈结构:使用
QStack
- 队列结构:使用
QQueue
5.2 性能优化
- 预分配内存:对于已知大小的容器,使用
reserve()
预分配内存 - 避免不必要的拷贝:使用引用或指针传递大型对象
- 选择合适的数据结构:根据访问模式选择最合适的容器
5.3 安全使用
- 检查边界:在访问容器元素前,确保索引有效
- 处理空容器:在使用容器前,检查是否为空
- 线程安全:在多线程环境中,使用适当的同步机制
六、总结
Qt6 提供了丰富的数据结构类,涵盖了从基本容器到高级数据结构的各种需求。合理选择和使用这些数据结构,可以大大提高开发效率和程序性能。同时,掌握这些数据结构的使用技巧和最佳实践,对于编写高效、健壮的 Qt 应用程序至关重要。
通过本文的介绍,希望读者能够更好地理解和使用 Qt6 中的常用数据结构,从而在实际开发中得心应手。