文章目录
-
-
- [QMap 全面解析(Qt5 vs Qt6)](#QMap 全面解析(Qt5 vs Qt6))
- 一、实现原理
- [二、核心函数(Qt5/Qt6 通用)](#二、核心函数(Qt5/Qt6 通用))
-
- [1. 基础操作](#1. 基础操作)
- [2. 查找操作](#2. 查找操作)
- [3. 遍历相关](#3. 遍历相关)
- [4. 高级操作](#4. 高级操作)
- 三、使用示例
-
- [1. 基础插入/查找/遍历](#1. 基础插入/查找/遍历)
- [2. 自定义键类型(需重载 < 运算符)](#2. 自定义键类型(需重载 < 运算符))
- [四、Qt5 vs Qt6 核心差异](#四、Qt5 vs Qt6 核心差异)
-
QMap 全面解析(Qt5 vs Qt6)
QMap 是 Qt 容器库中核心的有序键值对容器 ,基于红黑树(Red-Black Tree)实现,支持键的自动排序、快速查找/插入/删除,是 Qt 开发中替代 C++ 标准库 std::map 的常用选择。
一、实现原理
QMap 的底层是红黑树(一种自平衡的二叉搜索树),核心特性如下:
- 有序性 :所有键值对按键的升序 自动排序(默认按
<运算符,也可自定义比较器); - 平衡特性 :红黑树通过颜色标记(红/黑)和旋转操作保证树的高度始终为 O ( l o g n ) O(log n) O(logn),因此插入、删除、查找的时间复杂度均为 O ( l o g n ) O(log n) O(logn);
- 内存管理 :Qt5/Qt6 均采用隐式共享(Implicit Sharing,写时复制),多个 QMap 实例共享同一份数据,仅当修改时才复制,降低内存开销;
- 键唯一性 :QMap 不允许重复键(若插入重复键,新值会覆盖旧值);若需多值映射,需使用
QMultiMap(QMap 的子类)。
对比:C++
std::map同样基于红黑树,但 QMap 额外提供了 Qt 风格的 API、隐式共享、跨平台兼容性,且支持 Qt 特有的类型(如 QString、QVariant)。
二、核心函数(Qt5/Qt6 通用)
QMap 的函数可分为基础操作、查找、遍历、修改、辅助工具五类,以下是高频函数:
1. 基础操作
| 函数 | 功能 | 示例 |
|---|---|---|
QMap<Key, T>() |
构造空 QMap | QMap<int, QString> map; |
insert(Key k, T v) |
插入键值对(覆盖重复键) | map.insert(1, "Apple"); |
remove(Key k) |
删除指定键的项 | map.remove(1); |
clear() |
清空所有项 | map.clear(); |
size() |
返回元素个数 | int len = map.size(); |
isEmpty() |
判断是否为空 | if (map.isEmpty()) { ... } |
contains(Key k) |
判断是否包含指定键 | if (map.contains(2)) { ... } |
2. 查找操作
| 函数 | 功能 | 示例 |
|---|---|---|
value(Key k, T default=T()) |
获取键对应的值,无则返回默认值 | QString v = map.value(1, "None"); |
operator[](Key k) |
重载[],获取/设置值(无键则插入默认值) | map[1] = "Banana"; |
keys() |
返回所有键(升序) | QList<int> ks = map.keys(); |
values() |
返回所有值(按键序) | QList<QString> vs = map.values(); |
find(Key k) |
返回指向键的迭代器(无则返回 end()) | QMap<int, QString>::iterator it = map.find(1); |
constFind(Key k) |
常量迭代器(不可修改值) | QMap<int, QString>::const_iterator cit = map.constFind(1); |
3. 遍历相关
| 函数 | 功能 |
|---|---|
begin() / end() |
普通迭代器(起始/末尾) |
cbegin() / cend() |
常量迭代器(Qt5 新增,Qt6 完善) |
rbegin() / rend() |
反向迭代器(Qt5/6 均支持) |
4. 高级操作
| 函数 | 功能 |
|---|---|
swap(QMap &other) |
交换两个 QMap 的数据(无拷贝) |
take(Key k) |
删除键并返回对应值(无则返回默认值) |
unite(QMap &other) |
合并另一个 QMap(重复键覆盖) |
lowerBound(Key k) |
返回第一个 ≥k 的迭代器 |
upperBound(Key k) |
返回第一个 >k 的迭代器 |
三、使用示例
1. 基础插入/查找/遍历
cpp
#include <QCoreApplication>
#include <QMap>
#include <QDebug>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
// 1. 构造并插入数据
QMap<int, QString> fruitMap;
fruitMap.insert(3, "Orange");
fruitMap.insert(1, "Apple");
fruitMap.insert(2, "Banana");
fruitMap[4] = "Grape"; // 用[]插入(覆盖重复键)
// 2. 查找值
qDebug() << "键 2 的值:" << fruitMap.value(2); // 输出 "Banana"
qDebug() << "键 5 的值(默认):" << fruitMap.value(5, "Unknown"); // 输出 "Unknown"
// 3. 遍历(迭代器方式)
qDebug() << "\n迭代器遍历(有序):";
for (QMap<int, QString>::const_iterator it = fruitMap.cbegin(); it != fruitMap.cend(); ++it) {
qDebug() << "键:" << it.key() << " 值:" << it.value();
}
// 4. 遍历(foreach 方式,Qt 特有)
qDebug() << "\nforeach 遍历:";
foreach (int key, fruitMap.keys()) {
qDebug() << "键:" << key << " 值:" << fruitMap[key];
}
// 5. 删除元素
fruitMap.remove(3);
qDebug() << "\n删除键 3 后大小:" << fruitMap.size(); // 输出 3
return a.exec();
}
2. 自定义键类型(需重载 < 运算符)
cpp
// 自定义结构体作为键
struct Person {
QString name;
int age;
// 必须重载 < 运算符,否则 QMap 无法排序
bool operator<(const Person &other) const {
return age < other.age; // 按年龄升序
}
};
// 使用示例
QMap<Person, QString> personMap;
personMap.insert({ "Alice", 25 }, "Engineer");
personMap.insert({ "Bob", 30 }, "Designer");
四、Qt5 vs Qt6 核心差异
| 维度 | Qt5 | Qt6 |
|---|---|---|
| 底层实现 | 红黑树 + 隐式共享 | 核心仍为红黑树,但优化了内存布局(减少冗余) |
| 迭代器 | 1. cbegin()/cend() 新增(Qt5.1+) 2. 反向迭代器支持但性能一般 |
1. 迭代器性能优化(减少拷贝) 2. 新增 const_iterator 更严格的类型检查 |
| API 废弃 | 无重大废弃 | 1. 废弃 QMap::iterator::key() 的非 const 版本(避免修改键破坏排序) 2. 废弃 QMap::unite() 的非 const 参数重载 |
| 性能 | 1. 隐式共享拷贝开销中等 2. 大规模数据插入/删除略慢 | 1. 隐式共享优化(减少原子操作) 2. 红黑树节点内存布局优化,大规模操作提速 ~10% |
| 兼容性 | 支持 C++98/11 | 仅支持 C++17+,迭代器兼容 std::iterator_traits |
| QMultiMap | 继承 QMap,实现多值映射 | 逻辑不变,但底层与 QMap 共享优化后的红黑树代码 |
| 新增函数 | - | QMap::contains(const Key &k) const 优化(避免不必要的拷贝) 新增 QMap::emplace()(直接构造值,减少拷贝) |
关键注意:Qt6 中 QMap 的键类型必须是可比较的 (重载
<或提供自定义比较器),且禁止修改迭代器返回的键(Qt5 中允许但会导致未定义行为,Qt6 直接禁止)。
总结
- 核心特性:QMap 基于红黑树实现,有序、O(log n) 时间复杂度、隐式共享,键唯一(多值用 QMultiMap);
- 核心函数 :高频操作包括
insert()/value()/contains()/find(),遍历用迭代器或 foreach; - Qt5 vs Qt6:Qt6 优化了性能、严格了类型检查,废弃了不安全 API,仅支持 C++17+,核心逻辑无本质变化。
如果需要兼容 Qt5 和 Qt6,建议:① 优先使用 const_iterator 遍历;② 避免修改迭代器返回的键;③ 用 value() 替代 [] 查找(避免插入默认值)。