Qt 容器类笔记:QMap、QHash 与 QVector
·
https://github.com/0voice
一、QMap 详解
1. 底层实现
QMap 底层基于红黑树(自平衡二叉搜索树)实现,通过键的比较大小关系自动排序,保证插入、删除、查找操作的时间复杂度为 O (log n)。
2. 核心操作示例及说明
cpp运行
// 1. 定义QMap对象(键为QString类型,值为int类型)
QMap<QString, int> map1;
// 2. 插入键值对(两种方式)
map1["kobe"] = 24; // 下标法插入
map1.insert("James", 23); // insert()方法插入
qDebug() << map1; // 输出:QMap(("James",23)("kobe",24))(自动按key升序排列)
// 3. 继续插入新元素
map1.insert("KD", 7);
map1.insert("LK", 77);
qDebug() << map1; // 输出:QMap(("James",23)("KD",7)("LK",77)("kobe",24))
// 4. 删除元素(通过key删除)
map1.remove("kobe");
qDebug() << map1; // 输出:QMap(("James",23)("KD",7)("LK",77))
// 5. 遍历方式1:Java风格迭代器
QMapIterator<QString, int> isM(map1); // 迭代器初始化
while (isM.hasNext()) { // 判断是否有下一个元素
isM.next(); // 移动到下一个元素
qDebug() << isM.key() << ":" << isM.value(); // 获取键和值
}
// 6. 遍历方式2:STL风格常量迭代器
QMap<QString, int>::const_iterator stritr = map1.constBegin();
while (stritr != map1.constEnd()) { // 遍历到末尾结束
qDebug() << stritr.key() << ":" << stritr.value();
stritr++; // 迭代器自增
}
// 7. 查找操作
qDebug() << "key找value:" << map1.value("KD"); // 通过key查value,输出:7
qDebug() << "value找key:" << map1.key(7); // 通过value查key,输出:"KD"
// 8. 修改键值(insert()方法会覆盖已有key的value)
map1.insert("KD", 35); // 覆盖原"KD"的value(7→35)
qDebug() << map1; // 输出:QMap(("James",23)("KD",35)("LK",77))
// 9. 判断是否包含某个key
qDebug() << "是否包含LK:" << map1.contains("LK"); // 输出:true
3. 特性总结
- 键值对自动按 key 升序排列(依赖
operator<比较键) - 支持通过 key 快速查找 value,也支持通过 value 反向查找 key(但反向查找效率较低)
- 允许通过
insert()覆盖已有键的值,或通过operator[]直接修改 - 适合需要有序存储且频繁进行查找 / 修改的场景
二、QHash 详解
1. 底层实现
QHash 底层基于哈希表实现,通过哈希函数将 key 映射到哈希表的索引位置,平均时间复杂度为 O (1),最坏情况(哈希冲突严重)为 O (n)。
2. 核心操作示例及说明
cpp运行
// 1. 定义QHash对象(键为QString类型,值为int类型)
QHash<QString, int> qhash;
// 2. 插入键值对(两种方式)
qhash["key1"] = 1; // 下标法插入
qhash.insert("key2", 2); // insert()方法插入
qhash.insert("key3", 3);
// 3. 查找操作(通过key查value)
qDebug() << "key2的值:" << qhash["key2"]; // 输出:2
// 4. 遍历(STL风格迭代器)
QHash<QString, int>::iterator it = qhash.begin();
while (it != qhash.end()) {
qDebug() << it.key() << ":" << it.value(); // 输出顺序不固定(无排序)
it++;
}
// 5. 删除元素
qhash.remove("key1");
// 6. 判断是否包含key
qDebug() << "是否包含key3:" << qhash.contains("key3"); // 输出:true
3. 特性总结
- 键值对无固定顺序(不排序)
- 查找、插入、删除效率通常高于 QMap(平均 O (1))
- 对 key 的要求:需支持
operator==和qHash()函数(用于哈希计算) - 适合不关心顺序、追求极致查找效率的场景
三、QMap 与 QHash 的区别对比
| 特性 | QMap | QHash |
|---|---|---|
| 底层结构 | 红黑树(平衡二叉搜索树) | 哈希表 |
| 元素顺序 | 按 key 升序排列 | 无固定顺序 |
| 时间复杂度 | 插入 / 查找 / 删除均为 O (log n) | 平均 O (1),最坏 O (n) |
| 对 key 的要求 | 需重载operator< | 需重载operator==和qHash() |
| 内存占用 | 较高(红黑树节点存储额外指针) | 较低(哈希表结构更紧凑) |
| 适用场景 | 需要有序存储、频繁范围查询 | 无需排序、追求快速查找 |
| 迭代器稳定性 | 插入 / 删除不影响其他迭代器 | 插入可能导致迭代器失效 |
四、QVector 详解
1. 底层实现
QVector 底层基于动态数组(连续内存空间)实现,与 C++ 标准库的std::vector类似,通过预分配内存和动态扩容保证高效的元素访问。
2. 核心操作示例及说明
cpp运行
// 1. 定义QVector对象(存储int类型元素)
QVector<int> vec;
// 2. 插入元素
vec.append(10); // 尾部添加
vec.push_back(20); // 尾部添加(同append)
vec.insert(1, 15); // 在索引1位置插入15(原元素后移)
qDebug() << vec; // 输出:QVector(10, 15, 20)
// 3. 访问元素(两种方式)
qDebug() << "索引0的元素:" << vec[0]; // 下标访问(无越界检查)
qDebug() << "索引1的元素:" << vec.at(1); // at()方法(有越界检查,更安全)
// 4. 修改元素
vec[2] = 25; // 下标修改
qDebug() << vec; // 输出:QVector(10, 15, 25)
// 5. 遍历(三种方式)
// 方式1:下标遍历
for (int i = 0; i < vec.size(); ++i) {
qDebug() << vec[i];
}
// 方式2:STL风格迭代器
QVector<int>::iterator it = vec.begin();
while (it != vec.end()) {
qDebug() << *it;
it++;
}
// 方式3:C++11范围for循环
for (int val : vec) {
qDebug() << val;
}
// 6. 删除元素
vec.remove(1); // 删除索引1的元素
qDebug() << vec; // 输出:QVector(10, 25)
// 7. 其他常用操作
vec.resize(5); // 调整大小(不足补默认值0)
qDebug() << "容量:" << vec.capacity(); // 容量(预分配的内存大小)
vec.squeeze(); // 释放多余容量(容量=大小)
3. 特性总结
- 元素连续存储,支持随机访问(时间复杂度 O (1))
- 尾部插入 / 删除效率高(O (1)),中间插入 / 删除效率低(需移动元素,O (n))
- 自动扩容机制:当元素数量超过容量时,通常扩容为原容量的 2 倍(减少频繁分配内存)
- 适合需要频繁随机访问或尾部操作的场景(如存储列表数据、缓冲区等)
总结
- QMap:有序键值对,红黑树实现,适合需要排序和稳定查找的场景。
- QHash:无序键值对,哈希表实现,适合追求高效查找且不关心顺序的场景。
- QVector:动态数组,连续内存存储,适合频繁随机访问和尾部操作的场景。
根据具体需求选择合适的容器类,可显著提升程序性能和可读性。
更多推荐
所有评论(0)