当前位置: 首页 > news >正文

Qt容器类:QList、QMap等的高效使用

一、Qt容器类概述

Qt提供了一套丰富的容器类,这些容器类是基于模板实现的,用于存储和管理一组数据项。与C++标准库中的容器相比,Qt容器类更加方便、安全,并且提供了一些额外的功能。理解这些容器类的特性和适用场景,对于编写高效、可维护的Qt代码至关重要。

1.1 容器类的分类

Qt容器类主要分为两类:

  • 顺序容器:按顺序存储元素,如QList、QLinkedList、QVector、QStack、QQueue。
  • 关联容器:通过键来存储和访问元素,如QMap、QMultiMap、QHash、QMultiHash、QSet。

1.2 容器类的共同特性

  • 类型安全:基于模板实现,确保存储的元素类型一致。
  • 隐式共享:采用写时复制(Copy-on-Write)技术,减少内存使用和数据复制。
  • 可迭代:支持迭代器,方便遍历容器中的元素。
  • 可序列化:可以通过QDataStream进行序列化和反序列化。
  • 边界检查:调试模式下提供边界检查,提高代码安全性。

二、顺序容器类的使用

2.1 QList

QList是Qt中最常用的顺序容器,它提供了快速的随机访问和快速的尾部添加操作。在内部,QList使用数组实现,因此随机访问效率高。

示例:使用QList

#include <QList>
#include <QDebug>void testQList() {// 创建QList并添加元素QList<QString> list;list.append("apple");list.append("banana");list.append("cherry");// 使用<<操作符添加元素list << "date" << "elderberry";// 访问元素qDebug() << "第一个元素:" << list.first();  // 或list[0]qDebug() << "最后一个元素:" << list.last();  // 或list[list.size()-1]// 遍历元素 - 使用索引for (int i = 0; i < list.size(); ++i) {qDebug() << "元素" << i << ":" << list[i];}// 遍历元素 - 使用迭代器QList<QString>::const_iterator it;for (it = list.begin(); it != list.end(); ++it) {qDebug() << "迭代器元素:" << *it;}// 遍历元素 - 使用foreachforeach (const QString &str, list) {qDebug() << "foreach元素:" << str;}// 修改元素list[1] = "blueberry";// 插入元素list.insert(2, "grape");// 删除元素list.removeAt(3);// 检查元素是否存在bool exists = list.contains("apple");// 查找元素位置int index = list.indexOf("cherry");
}

2.2 QLinkedList

QLinkedList是一个真正的链表实现,提供了快速的插入和删除操作,但随机访问效率较低。

示例:使用QLinkedList

#include <QLinkedList>void testQLinkedList() {QLinkedList<int> linkedList;// 添加元素linkedList.append(10);linkedList.prepend(5);linkedList.insert(linkedList.end(), 15);// 遍历元素for (QLinkedList<int>::const_iterator it = linkedList.begin(); it != linkedList.end(); ++it) {qDebug() << *it;}// 删除元素linkedList.removeFirst();linkedList.removeLast();// 判断链表是否为空bool isEmpty = linkedList.isEmpty();
}

2.3 QVector

QVector提供了连续的内存存储,类似于C++的std::vector。它在随机访问和尾部添加元素时效率很高。

示例:使用QVector

#include <QVector>void testQVector() {QVector<double> vector;// 预分配空间vector.reserve(100);// 添加元素for (int i = 0; i < 10; ++i) {vector.append(i * 0.1);}// 访问元素double value = vector[5];// 调整大小vector.resize(15);  // 多余的元素将被默认构造vector.resize(8);   // 超出部分将被截断// 快速填充vector.fill(1.0);
}

三、关联容器类的使用

3.1 QMap

QMap是一个有序的键值对容器,它基于红黑树实现,保证元素按键的升序排列。

示例:使用QMap

#include <QMap>void testQMap() {QMap<QString, int> map;// 添加元素map["apple"] = 1;map["banana"] = 2;map["cherry"] = 3;// 另一种添加元素的方式map.insert("date", 4);// 访问元素int value = map["apple"];  // 如果键不存在,会插入一个默认值int value2 = map.value("banana");  // 更安全的访问方式int defaultValue = map.value("grape", 0);  // 指定默认值// 检查键是否存在bool exists = map.contains("cherry");// 遍历元素 - 按键的顺序QMap<QString, int>::const_iterator it;for (it = map.begin(); it != map.end(); ++it) {qDebug() << "键:" << it.key() << "值:" << it.value();}// 删除元素map.remove("banana");// 获取所有键和值QList<QString> keys = map.keys();QList<int> values = map.values();
}

3.2 QHash

QHash是一个无序的键值对容器,它基于哈希表实现,提供了更快的查找和插入操作。

示例:使用QHash

#include <QHash>void testQHash() {QHash<QString, int> hash;// 添加元素hash["apple"] = 1;hash["banana"] = 2;hash["cherry"] = 3;// 访问元素int value = hash["apple"];// 检查键是否存在bool exists = hash.contains("cherry");// 遍历元素 - 无序QHash<QString, int>::const_iterator it;for (it = hash.begin(); it != hash.end(); ++it) {qDebug() << "键:" << it.key() << "值:" << it.value();}// 删除元素hash.remove("banana");// 获取键的数量int size = hash.size();
}

3.3 QMultiMap和QMultiHash

QMultiMap和QMultiHash是允许一个键对应多个值的容器。

示例:使用QMultiMap

#include <QMultiMap>void testQMultiMap() {QMultiMap<QString, int> multiMap;// 添加多个值multiMap.insert("apple", 1);multiMap.insert("apple", 2);multiMap.insert("apple", 3);// 获取所有值QList<int> values = multiMap.values("apple");// 遍历所有键值对QMultiMap<QString, int>::const_iterator it;for (it = multiMap.begin(); it != multiMap.end(); ++it) {qDebug() << "键:" << it.key() << "值:" << it.value();}// 删除所有"apple"的键值对multiMap.remove("apple");
}

四、容器类的性能比较与选择

4.1 顺序容器性能比较

操作QListQLinkedListQVector
随机访问极快很慢极快
头部插入/删除快(如果预分配)极快
尾部插入/删除极快极快极快
中间插入/删除
内存预分配支持不支持支持

4.2 关联容器性能比较

操作QMapQHash
插入较慢(红黑树)极快(哈希表)
查找较慢(O(log n))极快(平均O(1))
删除较慢(红黑树)极快(哈希表)
有序性有序无序
键的类型要求必须支持<运算符必须支持==运算符和qHash()函数

4.3 容器选择建议

  • QList:大多数情况下的首选顺序容器,除非需要频繁在中间插入/删除元素。
  • QLinkedList:需要频繁在中间插入/删除元素时使用。
  • QVector:需要连续内存存储或与C API交互时使用。
  • QMap:需要有序存储或键的类型不支持哈希函数时使用。
  • QHash:需要快速查找时使用。
  • QMultiMap/QMultiHash:需要一个键对应多个值时使用。

五、容器类的高级用法

5.1 隐式共享与性能

Qt容器类使用隐式共享技术,在对象被复制时并不立即复制数据,而是在修改时才进行复制。这可以提高性能,但在某些情况下需要注意。

示例:隐式共享的影响

void testImplicitSharing() {QList<int> list1;list1 << 1 << 2 << 3;// 复制list1到list2,此时不会复制数据QList<int> list2 = list1;// 此时仍然没有复制数据qDebug() << "list2在修改前是否与list1共享数据:" << list2.isDetached();// 修改list2,此时才会复制数据list2.append(4);qDebug() << "list2在修改后是否与list1共享数据:" << list2.isDetached();
}

5.2 容器的序列化与反序列化

Qt容器类可以通过QDataStream进行序列化和反序列化。

示例:容器的序列化与反序列化

#include <QFile>
#include <QDataStream>void saveContainerToFile(const QMap<QString, int> &map, const QString &fileName) {QFile file(fileName);if (file.open(QIODevice::WriteOnly)) {QDataStream stream(&file);stream << map;file.close();}
}QMap<QString, int> loadContainerFromFile(const QString &fileName) {QMap<QString, int> map;QFile file(fileName);if (file.open(QIODevice::ReadOnly)) {QDataStream stream(&file);stream >> map;file.close();}return map;
}

5.3 使用STL风格的迭代器

Qt容器类支持STL风格的迭代器,方便与STL算法结合使用。

示例:使用STL风格的迭代器

#include <algorithm>void testSTLIterators() {QList<int> list;list << 5 << 3 << 1 << 4 << 2;// 使用STL算法排序std::sort(list.begin(), list.end());// 使用STL算法查找QList<int>::iterator it = std::find(list.begin(), list.end(), 3);if (it != list.end()) {qDebug() << "找到元素:" << *it;}
}

六、总结

Qt容器类提供了丰富、高效的数据存储和管理功能,能够满足各种应用场景的需求。顺序容器如QList、QLinkedList和QVector适用于按顺序存储元素的场景,而关联容器如QMap和QHash则适用于通过键来存储和访问元素的场景。在选择容器类时,需要根据具体的应用场景和性能需求来决定。理解容器类的隐式共享机制、序列化功能和STL风格的迭代器等高级用法,可以帮助我们编写更加高效、灵活的代码。掌握了Qt容器类的使用,我们就能在开发过程中更加得心应手地处理各种数据结构和算法问题。

http://www.dtcms.com/a/294598.html

相关文章:

  • 2025年7月份实时最新获取地图边界数据方法,省市区县街道多级联动【文末附实时geoJson数据下载】
  • 闲庭信步使用图像验证平台加速FPGA的开发:第三十一课——车牌识别的FPGA实现(3)车牌字符分割预处理
  • 从零开始学习Dify-Excel数据可视化(四)
  • PHP面向对象高级应用:依赖注入、服务容器与PSR标准实现
  • STL学习(四、队列和堆栈)
  • CSP-J系列【2023】P9751 [CSP-J 2023] 旅游巴士题解
  • 变频器实习DAY12
  • 接入海康设备mark全是false解决方案
  • Elasticsearch整合:Repository+RestClient双模式查询优化
  • 【杂谈】-代理协议:重塑AI协作新生态,开启智能互联新时代
  • 开闭原则在C++中的实现
  • InfluxDB HTTP API 接口调用详解(二)
  • [HarmonyOS] 鸿蒙LiteOS-A内核深度解析 —— 面向 IoT 与智能终端的“小而强大”内核
  • 算法第27天|贪心算法:合并区间 、单调递增的数字
  • 面试实战,问题七,Object类中包含哪些常用方法及其作用,怎么回答
  • biji 1
  • 开源 Arkts 鸿蒙应用 开发(十)通讯--Http数据传输
  • RAG深入理解和简易实现
  • Linux基础服务(Crontab和NFS)
  • 解决报错:ModuleNotFoundError: No module named ‘_pafprocess‘
  • 测试左移方法论
  • NX741NX777美光固态闪存NX783NX791
  • 算法思想之队列
  • 精准医学在肿瘤治疗中的应用案例研究
  • 终端VS命令解释器(Linux Windows)
  • 一招拿捏Windows的软件,仅仅1.22M
  • 如何硬解析 .shp 文件中的几何体,拯救 .dbf、.shx 等文件缺失的 ESRI Shapefile 格式文件
  • (Python)类的练习与巩固(图书管理系统扩展)(类与方法的基础教程)(if条件扩展)(动态类型)(Python教程)
  • LLC协议支持哪些类型的帧?它们各自的功能是什么?
  • IAR Embedded Workbench for ARM 8.1 安装教程