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 的区别对比

特性QMapQHash
底层结构红黑树(平衡二叉搜索树)哈希表
元素顺序按 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:动态数组,连续内存存储,适合频繁随机访问和尾部操作的场景。

根据具体需求选择合适的容器类,可显著提升程序性能和可读性。

更多推荐