C++ Qt开发:使用关联容器类
当我们谈论编程中的数据结构时,顺序容器是不可忽视的一个重要概念。顺序容器是一种能够按照元素添加的顺序来存储和检索数据的数据结构。它们提供了简单而直观的方式来组织和管理数据,为程序员提供了灵活性和性能的平衡。
Qt 中提供了丰富的容器类,用于方便地管理和操作数据。这些容器类涵盖了各种不同的用途,从简单的动态数组到复杂的映射和集合。本章我们将主要学习关联容器,主要包括 QMap ,QSet和 QHash,它们提供了键值对存储和检索的功能,允许通过键来快速查找值。
1.1 QMap
QMap 是 Qt 中的有序关联容器,用于存储键值对,并按键的升序进行排序。以下是关于 QMap 的概述:
1.1.1 特点和用途
- 有序性:
QMap中的元素是有序的,按照键的升序进行排列。 - 唯一键: 每个键在
QMap中是唯一的,不允许重复键。 - 键值对存储: 存储键值对,每个键关联一个值。
- 性能: 插入和查找操作的平均复杂度是 O(log n),适用于需要按键排序并进行频繁查找的场景。
1.1.2 函数和功能
以下是关于 QMap 常用函数及其功能的总结:
| 函数 | 功能 |
|---|---|
insert(const Key &key, const T &value) |
向 QMap 中插入键值对。 |
insertMulti(const Key &key, const T &value) |
向 QMap 中插入允许相同键的多个值。 |
remove(const Key &key) |
移除指定键的元素。 |
value(const Key &key) const |
返回指定键的值。 |
contains(const Key &key) const |
判断是否包含指定键。 |
isEmpty() const |
判断 QMap 是否为空。 |
size() const |
返回 QMap 中键值对的数量。 |
clear() |
清空 QMap 中的所有元素。 |
keys() const |
返回 QMap 中所有键的列表。 |
values() const |
返回 QMap 中所有值的列表。 |
begin() |
返回指向 QMap 开始位置的迭代器。 |
end() |
返回指向 QMap 结束位置的迭代器。 |
constBegin() const |
返回指向 QMap 开始位置的常量迭代器。 |
constEnd() const |
返回指向 QMap 结束位置的常量迭代器。 |
find(const Key &key) const |
返回指向 QMap 中指定键的迭代器。 |
lowerBound(const Key &key) const |
返回指向 QMap 中不小于指定键的第一个元素的迭代器。 |
upperBound(const Key &key) const |
返回指向 QMap 中大于指定键的第一个元素的迭代器。 |
count(const Key &key) const |
返回指定键的数量。 |
toStdMap() const |
将 QMap 转换为 std::map。 |
这些函数提供了对 QMap 中键值对的插入、删除、查找和遍历等操作。根据需求选择适当的函数以满足操作要求。
1.1.3 应用案例
正如如下代码所示,我们提供了QMap<QString,QString>字典类型的关联数组,该数组中一个键映射对应一个值,QMap容器是按照顺序存储的,如果项目中不在意顺序可以使用QHash容器,使用QHash效率更高些。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QtGlobal>
#include <QMap>
#include <QMapIterator>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<QString,QString> map;
map["1001"] = "admin";
map["1002"] = "guest";
map.insert("1003","lyshark");
map.insert("1004","lucy");
// map.remove("1002");
// 根据键值对查询属性
std::cout << map["1002"].toStdString().data() << std::endl;
std::cout << map.value("1003").toStdString().data() << std::endl;
std::cout << map.key("admin").toStdString().data() << std::endl;
// 使用STL语法迭代枚举Map键值对
QMap<QString,QString>::const_iterator x;
for(x=map.constBegin();x != map.constEnd(); ++x)
{
std::cout << x.key().toStdString().data() << " : ";
std::cout << x.value().toStdString().data() << std::endl;
}
// 使用STL语法实现修改键值对
QMap<QString,QString>::iterator write_x;
write_x = map.find("1003");
if(write_x !=map.end())
write_x.value()= "you ary in";
// 使用QTglobal中自带的foreach遍历键值对
QString each;
// --> 单循环遍历
foreach(const QString &each,map.keys())
{
std::cout << map.value(each).toStdString().data() << std::endl;
}
// --> 多循环遍历
foreach(const QString &each,map.uniqueKeys())
{
foreach(QString x,map.value(each))
{
std::cout << each.toStdString().data() << " : ";
std::cout << x.toStdString().data() << std::endl;
}
}
return a.exec();
}
上述代码是如何使用QMap容器,其实还有一个QMultiMap容器,该容器其实是QMap的一个子集,用于处理多值映射的类,也就是说传统QMap只能是一对一的关系,而QMultiMap则可以实现一个Key对应多个Value或者是反过来亦可,实现一对多的关系。
如果总结起来可以发现两者的异同点;
QMap
- 唯一键:
QMap中每个键都是唯一的,不允许重复键。 - 键排序:
QMap中的元素是按键的升序排列的。 - 使用场景: 适用于需要键值对有序且键唯一的场景。
QMultiMap
- 允许重复键:
QMultiMap中可以包含重复的键,即多个键可以映射到相同的值。 - 键排序:
QMultiMap中的元素是按键的升序排列的。 - 使用场景: 适用于允许键重复,并且需要键值对有序的场景。
相同点
- 键值对: 都是用于存储键值对的容器。
- 有序性: 元素在容器中是有序的,按键的升序排列。
不同点
- 键唯一性:
QMap中每个键都是唯一的,而QMultiMap允许重复的键。 - 使用场景:
QMap适用于需要键唯一的情况,而QMultiMap适用于允许键重复的情况。
如下所示,展示了如何使用QMultiMap实现一对多的映射关系;
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QList>
#include <QMultiMap>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMultiMap<QString,QString> mapA,mapB,mapC,mapD;
mapA.insert("lyshark","1000");
mapA.insert("lyshark","2000");
mapB.insert("admin","3000");
mapB.insert("admin","4000");
mapC.insert("admin","5000");
// 获取到里面的所有key=lyshark的值
QList<QString> ref;
ref = mapA.values("lyshark");
for(int x=0;x<ref.size();++x)
{
std::cout << ref.at(x).toStdString().data() << std::endl;
}
// 两个key相同可相加后输出
mapD = mapB + mapC;
ref = mapD.values("admin");
for(int x=0;x<ref.size();x++)
{
std::cout << ref.at(x).toStdString().data() << std::endl;
}
return a.exec();
}
1.2 QHash
QHash 是一个无序的关联容器,它存储键值对,但与 QMap 不同,QHash 不会对键进行排序。
1.2.1 特点和用途
键值对存储:
QHash中的元素以键值对的形式存储,但与QMap不同,QHash中的元素是无序的。无序性:
QHash中的元素是无序的,没有特定的排列顺序。唯一键: 每个键在
QHash中是唯一的,不允许重复键。性能: 插入和查找操作的平均复杂度是 O(1),适用于需要快速插入和查找的场景。
1.2.2 函数和功能
以下是关于 QHash 常用函数及其功能的总结:
| 函数 | 功能 |
|---|---|
insert(const Key &key, const T &value) |
向 QHash 中插入键值对。 |
insertMulti(const Key &key, const T &value) |
向 QHash 中插入允许相同键的多个值。 |
remove(const Key &key) |
移除指定键的元素。 |
value(const Key &key) const |
返回指定键的值。 |
contains(const Key &key) const |
判断是否包含指定键。 |
isEmpty() const |
判断 QHash 是否为空。 |
size() const |
返回 QHash 中键值对的数量。 |
clear() |
清空 QHash 中的所有元素。 |
keys() const |
返回 QHash 中所有键的列表。 |
values() const |
返回 QHash 中所有值的列表。 |
begin() |
返回指向 QHash 开始位置的迭代器。 |
end() |
返回指向 QHash 结束位置的迭代器。 |
constBegin() const |
返回指向 QHash 开始位置的常量迭代器。 |
constEnd() const |
返回指向 QHash 结束位置的常量迭代器。 |
find(const Key &key) const |
返回指向 QHash 中指定键的迭代器。 |
count(const Key &key) const |
返回指定键的数量。 |
unite(const QHash &other) |
合并两个 QHash,将 other 中的元素合并到当前 QHash。 |
intersect(const QHash &other) |
保留两个 QHash 中共有的元素,删除其他元素。 |
subtract(const QHash &other) |
从当前 QHash 中移除与 other 共有的元素。 |
toStdHash() const |
将 QHash 转换为 std::unordered_map。 |
这些函数提供了对 QHash 中键值对的插入、删除、查找和遍历等操作。根据需求选择适当的函数以满足操作要求。
1.2.3 应用案例
QHash与QMap其实是一样的,如果不需要对键值对进行排序那么使用QHash将会得到更高的效率,正是因为Hash的无序,才让其具备了更加高效的处理能力。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QHash>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QHash<QString, QString> hash;
hash["1001"] = "admin";
hash["1002"] = "guest";
hash.insert("1003", "lyshark");
hash.insert("1004", "lucy");
// hash.remove("1002");
// 根据键值对查询属性
std::cout << hash["1002"].toStdString().data() << std::endl;
std::cout << hash.value("1003").toStdString().data() << std::endl;
std::cout << hash.key("admin").toStdString().data() << std::endl;
// 使用STL语法迭代枚举Hash键值对
QHash<QString, QString>::const_iterator x;
for (x = hash.constBegin(); x != hash.constEnd(); ++x)
{
std::cout << x.key().toStdString().data() << " : ";
std::cout << x.value().toStdString().data() << std::endl;
}
// 使用STL语法实现修改键值对
QHash<QString, QString>::iterator write_x;
write_x = hash.find("1003");
if (write_x != hash.end())
write_x.value() = "you are in";
// 使用Qt中自带的foreach遍历键值对
QString each;
// --> 单循环遍历
foreach (const QString &each, hash.keys())
{
std::cout << hash.value(each).toStdString().data() << std::endl;
}
// --> 多循环遍历
foreach (const QString &each, hash.uniqueKeys())
{
foreach (QString x, hash.values(each))
{
std::cout << each.toStdString().data() << " : ";
std::cout << x.toStdString().data() << std::endl;
}
}
return a.exec();
}
这里需要说明一点,与QMap一样,QHash也能够使用QMultiHash其操作上与QMultiMap保持一致,此处读者可自行尝试。
1.3 QSet
QSet 是 Qt 中的无序关联容器,类似于 C++ 标准库的 std::unordered_set。它主要用于存储唯一值,而不关心元素的顺序。以下是关于 QSet 的概述:
1.3.1 特点和用途
- 无序性:
QSet中的元素是无序的,没有特定的排列顺序。 - 唯一值: 每个值在
QSet中是唯一的,不允许重复值。 - 性能: 适用于需要快速查找和检索唯一值的场景,性能比有序容器(如
QMap)更高。 - 底层实现: 使用哈希表实现,因此插入和查找操作的平均复杂度是 O(1)。
1.3.2 函数和功能
以下是关于 QSet 常用函数及其功能的总结:
| 函数 | 功能 |
|---|---|
insert(const T &value) |
向 QSet 中插入元素。 |
contains(const T &value) const |
判断是否包含指定元素。 |
remove(const T &value) |
移除指定元素。 |
isEmpty() const |
判断 QSet 是否为空。 |
size() const |
返回 QSet 中元素的数量。 |
clear() |
清空 QSet 中的所有元素。 |
unite(const QSet &other) |
合并两个 QSet,将 other 中的元素合并到当前 QSet。 |
intersect(const QSet &other) |
保留两个 QSet 中共有的元素,删除其他元素。 |
subtract(const QSet &other) |
从当前 QSet 中移除与 other 共有的元素。 |
begin() |
返回指向 QSet 开始位置的迭代器。 |
end() |
返回指向 QSet 结束位置的迭代器。 |
constBegin() const |
返回指向 QSet 开始位置的常量迭代器。 |
constEnd() const |
返回指向 QSet 结束位置的常量迭代器。 |
这些函数提供了对 QSet 中元素的插入、删除、查找和遍历等操作。QSet 是一个无序容器,用于存储唯一的元素。根据需求选择适当的函数以满足操作要求。
1.3.3 应用案例
QSet 集合容器,是基于散列表(哈希表)的集合模板,存储顺序同样不定,查找速度最快,其内部使用QHash实现。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QSet>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSet<QString> set;
set << "dog" << "cat" << "tiger";
// 测试某值是否包含于集合
if(set.contains("cat"))
{
std::cout << "include" << std::endl;
}
return a.exec();
}
1.4 嵌套案例总结
1.4.1 QList与QMap组合
代码通过结合使用 QList 和 QMap 实现了数据的嵌套存储。具体而言,通过在 QMap 中存储键值对,其中键是时间字符串,而值是包含浮点数数据的 QList。这种结构使得可以方便地按时间检索相关联的数据集。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QtGlobal>
#include <QList>
#include <QMap>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<QString,QList<float>> map;
QList<float> ptr;
// 指定第一组数据
ptr.append(10.1);
ptr.append(12.5);
ptr.append(22.3);
map["10:10"] = ptr;
// 指定第二组数据
ptr.clear();
ptr.append(102.2);
ptr.append(203.2);
ptr.append(102.1);
map["11:20"] = ptr;
// 输出所有的数据
QList<float> tmp;
foreach(QString each,map.uniqueKeys())
{
tmp = map.value(each);
std::cout << "Time: " << each.toStdString().data() << std::endl;
for(qint32 x=0;x<tmp.count();x++)
{
std::cout << tmp[x]<< std::endl;
}
}
return a.exec();
}
在示例中,两组数据分别对应不同的时间键,每组数据存储在相应的 QList 中。最后,通过迭代输出了所有数据,以时间为键检索相应的数据集,并将每个数据集中的浮点数逐个输出。整体而言,这种数据结构的嵌套使用有助于组织和检索多维度的数据。
1.4.2 QList合并为QMap
通过使用 QList 存储头部信息(Header)和相应的数值信息(Values),然后通过循环迭代将两个列表合并为一个 QMap。在这个 QMap 中,头部信息作为键,而数值作为相应的值,形成了一个键值对应的字典结构。最后,通过 QMap 的键值对操作,输出了特定字典中的数据。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QtGlobal>
#include <QList>
#include <QMap>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<QString> Header = {"MemTotal","MemFree","Cached","SwapTotal","SwapFree"};
QList<float> Values = {12.5,46.8,68,100.3,55.9};
QMap<QString,float> map;
// 将列表合并为一个字典
for(int x=0;x<Header.count();x++)
{
QString head = Header[x].toStdString().data();
float val = Values[x];
map[head] = val;
}
// 输出特定字典中的数据
std::cout << map.key(100.3).toStdString().data() << std::endl;
std::cout << map.value("SwapTotal") << std::endl;
return a.exec();
}
整体而言,这样的数据结构使得能够更方便地按照特定的头部信息检索相应的数值。
1.4.3 QMap拆分为QList
这段代码演示了如何使用 QMap 存储键值对,并分别将键和值存储到两个 QList 中。首先,通过 Display 函数输出了 QMap 中的键值对。
接着,通过 map.keys() 和 map.values() 分别获取 QMap 中的所有键和值,将它们存储到两个 QList 中,并使用循环分别输出了这两个列表的内容。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QtGlobal>
#include <QList>
#include <QMap>
void Display(QMap<QString,float> map)
{
foreach(const QString &each,map.uniqueKeys())
{
std::cout << each.toStdString().data() << std::endl;
std::cout << map.value(each) << std::endl;
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<QString,float> map;
map["MemTotal"] = 12.5;
map["MemFree"] = 32.1;
map["Cached"] = 19.2;
Display(map);
QList<QString> map_key;
QList<float> map_value;
// 分别存储起来
map_key = map.keys();
map_value = map.values();
// 输出所有的key值
for(int x=0;x<map_key.count();x++)
{
std::cout << map_key[x].toStdString().data() << std::endl;
}
// 输出所有的value值
for(int x=0;x<map_value.count();x++)
{
std::cout << map_value[x] << std::endl;
}
return a.exec();
}
1.4.4 QList结构体排序
实现对包含结构体 MyStruct 的 QList 进行排序,并输出排序后的结果。首先,定义了一个包含整数的 QList,通过 std::sort 函数按从大到小的顺序对该列表进行排序,并使用 Display 函数输出排序后的结果。
其次,定义结构体 MyStruct,其中包含两个成员变量 uuid 和 uname。创建一个存储该结构体的 QList,并添加了几个结构体对象。通过 devListSort 函数,以结构体的 uuid 成员进行排序,并使用循环输出排序后的结果。
#include <QCoreApplication>
#include <iostream>
#include <QString>
#include <QtGlobal>
#include <QList>
struct MyStruct
{
int uuid;
QString uname;
};
void Display(QList<int> ptr)
{
foreach(const int &each,ptr)
std::cout << each << " ";
std::cout << std::endl;
}
// 由大到小排列
int compare(const int &infoA,const int &infoB)
{
return infoA > infoB;
}
// 针对结构体的排序方法
void devListSort(QList<MyStruct> *list)
{
std::sort(list->begin(),list->end(),[](const MyStruct &infoA,const MyStruct &infoB)
{
return infoA.uuid < infoB.uuid;
});
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 定义并对单一数组排序
QList<int> list = {56,88,34,61,79,82,34,67,88,1};
std::sort(list.begin(),list.end(),compare);
Display(list);
// 定义并对结构体排序
QList<MyStruct> list_struct;
MyStruct ptr;
ptr.uuid=1005;
ptr.uname="admin";
list_struct.append(ptr);
ptr.uuid=1002;
ptr.uname = "guest";
list_struct.append(ptr);
ptr.uuid = 1000;
ptr.uname = "lyshark";
list_struct.append(ptr);
devListSort(&list_struct);
for(int x=0;x< list_struct.count();x++)
{
std::cout << list_struct[x].uuid << " ---> ";
std::cout << list_struct[x].uname.toStdString().data() << std::endl;
}
return a.exec();
}
上述这段代码演示了如何对一个包含整数的列表和一个包含结构体的列表进行排序,并输出排序后的结果。在结构体排序的情况下,使用了自定义的排序方法 devListSort,该方法按照结构体的 uuid 成员进行升序排序。
C++ Qt开发:使用关联容器类的更多相关文章
- Qt中的常用容器类(解释比较全面,有插图)
在Qt库中为我们提供了一系列的基于模板的容器类.这些类可以被用来存储特定类型的项.例如,如果你需要一个大小可以变得QString数组,那么可以使用QVector<QString>. 这些容 ...
- Qt开发的应用记录读取用户习惯设置的方法
Qt开发的应用记录读取用户习惯设置的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/w ...
- Qt开发技术:图形视图框架(二)场景QGraphicsScene、QGraphicsItem与QGraphicsView详解
前话 Qt的图形视图框架,最核心的三个类为:QGraphicsScene.QGraphicsItem与QGraphicsView. 基于图形框架的高级白板软件Demo QGraphicsSce ...
- win使用MSYS2安装Qt开发环境
原文链接 MSYS2 下载地址: pacman的具体用法 有pacman的具体使用方法.我们首先对系统升级 我们首先对系统升级 pacman -Syu 就会检测整个系统可以升级的组件,并自动下载安装, ...
- 细数Qt开发的各种坑(欢迎围观)
1:Qt的版本多到你数都数不清,多到你开始怀疑人生.从4.6开始到5.8,从MSVC编译器到MINGW编译器,从32位到64位,从Windows到Linux到MAC.MSVC版本还必须安装对应的VS2 ...
- 用Qt开发第一个Hello World程序
配置好Qt的环境变量之后,我们才可以进行下面的通过终端来使用Qt开发这个第一个程序 因为Qt的文件路径不能有中文否则会报错,所以一般都把工程文件都建立在根目录 我们创建的Qt程序包含两个部分:1.GU ...
- 第一章 搭建Qt开发环境
第一章 搭建Qt开发环境 1.到http://download.qt-project.org/archive/上下载Qt的源码包.我下载的是qt-everywhere-opensource-src-4 ...
- Ubuntu 12.04下搭建Qt开发环境
http://download.qt.io/official_releases/qt/ Ubuntu 环境下Gtk与Qt编译环境安装与配置(系统环境是Ubuntu 12.04) 1.配置基础开发环境G ...
- QT开发pjsip的VOIP,A8平台运行
QT开发pjsip的VOIP 开发环境 平台:A8 环境:Linux-3.0.8 实现功能:使用QT开发VOIP进行初始化.拨号.挂起 测试工具:minisipserver服务器 效果 界面: min ...
- 基于QT开发的第三方库
基于Qt开发的第三方库 分类: Qt2014-02-12 11:34 1738人阅读 评论(0) 收藏 举报 QT第三方库 目录(?)[+] 文章来源:http://blog.csdn.net ...
随机推荐
- 免费拥有自己的 Github 资源加速器
TurboHub 是一个免费的 Github 资源加速下载站点,可以帮助你快速下载 Github 上的资源.其核心逻辑是通过 Azure Static Web Apps 服务和 Azure Funct ...
- 【pandas小技巧】--数据转置
所谓数据转置,就是是将原始数据表格沿着对角线翻折,使原来的行变成新的列,原来的列变成新的行,从而更方便地进行数据分析和处理. pandas中DataFrame的转置非常简单,每个DataFrame对象 ...
- 论文解读(CBL)《CNN-Based Broad Learning for Cross-Domain Emotion Classification》
Note:[ wechat:Y466551 | 付费咨询,非诚勿扰 ] 论文信息 论文标题:CNN-Based Broad Learning for Cross-Domain Emotion Clas ...
- 【AI绘画模型汇总】分享5个国内实用的AI绘画模型网站-C站AI模型平替网站
鉴于大家未必会有魔法工具访问civitai(C站)下载AI模型,这里我搜集整理了5个实用的国内版AI模型素材库,无障碍访问下载Stable diffusion模型. 1.LiblibAI 访问速度快, ...
- C# 合并Word文档
需要安装NuGet程序包 Spire.Doc DocX 注:DocX包去除警告提示用 Spire.Doc.Document document = new Spire.Doc.Document();// ...
- 性能调优 session 1 - 计算机体系结构 量化研究方法
近期本人参与的存储系统项目进入到性能调优阶段,当前系统的性能指标离项目预期目标还有较大差距.本人一直奉行"理论指导下的实践",尤其在调试初期,更要抓住主要矛盾,投入最少的资源来获取 ...
- 入门篇-其之四-字符串String的简单使用
什么是字符串? 在Java编程语言中,字符串用于表示文本数据. 字符串(String)属于引用数据类型,根据String的源码,其头部使用class进行修饰,属于类,即引用数据类型. 字符串的表示 字 ...
- Aveva Marine VBNET 编程系列-搭建开发框架
引用的Dll Aveva.ApplicationFramework.dll Aveva.ApplicationFramework.Presentation 菜单展示效果 创建Attribute,用于反 ...
- Go 语言开发环境搭建
Go 语言开发环境搭建 目录 Go 语言开发环境搭建 一. GO 环境安装 1.1 下载 1.2 Go 版本的选择 1.3 安装 1.3.1 Windows安装 1.3.2 Linux下安装 1.3. ...
- ndk开发之native层访问java层
一.native层访问java层的成员变量 java层的成员变量可以分为实例变量和静态变量,不过他们的访问方法比较类似,可以分为以下三步: 获取java类对应的jclass对象 获取需要访问的成员变量 ...