首页 > 编程语言 >C++ Qt开发:使用关联容器类

C++ Qt开发:使用关联容器类

时间:2023-12-24 19:33:15浏览次数:50  
标签:容器 const Qt map C++ 键值 QHash include QMap


当我们谈论编程中的数据结构时,顺序容器是不可忽视的一个重要概念。顺序容器是一种能够按照元素添加的顺序来存储和检索数据的数据结构。它们提供了简单而直观的方式来组织和管理数据,为程序员提供了灵活性和性能的平衡。

Qt 中提供了丰富的容器类,用于方便地管理和操作数据。这些容器类涵盖了各种不同的用途,从简单的动态数组到复杂的映射和集合。本章我们将主要学习关联容器,主要包括 QMapQSetQHash,它们提供了键值对存储和检索的功能,允许通过键来快速查找值。

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 中的元素是按键的升序排列的。
  • 使用场景: 适用于允许键重复,并且需要键值对有序的场景。
相同点
  1. 键值对: 都是用于存储键值对的容器。
  2. 有序性: 元素在容器中是有序的,按键的升序排列。
不同点
  1. 键唯一性: QMap 中每个键都是唯一的,而 QMultiMap 允许重复的键。
  2. 使用场景: 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 应用案例

QHashQMap其实是一样的,如果不需要对键值对进行排序那么使用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组合

代码通过结合使用 QListQMap 实现了数据的嵌套存储。具体而言,通过在 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结构体排序

实现对包含结构体 MyStructQList 进行排序,并输出排序后的结果。首先,定义了一个包含整数的 QList,通过 std::sort 函数按从大到小的顺序对该列表进行排序,并使用 Display 函数输出排序后的结果。

其次,定义结构体 MyStruct,其中包含两个成员变量 uuiduname。创建一个存储该结构体的 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 成员进行升序排序。


标签:容器,const,Qt,map,C++,键值,QHash,include,QMap
From: https://blog.51cto.com/lyshark/8956806

相关文章

  • C++ Qt开发:Qt的安装与配置
    Qt是一种C++编程框架,用于构建图形用户界面(GUI)应用程序和嵌入式系统。Qt由Qt公司(前身为Nokia)开发,提供了一套跨平台的工具和类库,使开发者能够轻松地创建高效、美观、可扩展的应用程序。其被广泛用于开发桌面应用程序、嵌入式系统、移动应用程序等。无论是初学者还是经验丰富的开发者,Q......
  • C++ Qt开发:字符串QString容器
    在Qt框架中,QString是一个强大而灵活的字符串容器,专为处理Unicode字符而设计。它提供了许多方便的方法来操作和处理字符串,使得在跨平台开发中能够轻松地进行文本操作。QString是Qt开发中不可或缺的一部分,它的灵活性和强大的功能使其成为处理文本和字符串操作的理想选择。本篇......
  • C++的nan、inf
    ( 2022-09-3000:28:51编辑完的,雪藏了很久,今天有时间了,把浮点数除法搜来补上)上周地图经纬度出的bug搞得我精疲力竭,总是莫名其妙的就点就飞到不知道哪里去了。qt版本又旧没有isNan函数,愣是找了2天多。最后发现是double数据传递给float出问题了。软件搭架子的工作多了,数值计算这里的......
  • Go编程基础教程:Go容器化技术
    作者:禅与计算机程序设计艺术1.背景介绍目前互联网服务开发已经从单体应用模式升级到微服务架构模式。在微服务架构模式下,服务之间会相互调用,为了更好地管理和调优这些分布式系统,需要对其进行容器化,使得各个服务可以独立部署、资源分配、隔离等方面更加灵活高效。本文将通过Go语言......
  • C++ Qt开发:如何使用信号与槽
    在Qt中,信号与槽(SignalandSlot)是一种用于对象之间通信的机制。是Qt框架引以为傲的一项机制,它带来了许多优势,使得Qt成为一个强大且灵活的开发框架之一。信号与槽的关联通过QObject::connect函数完成。这样的机制使得对象能够以一种灵活而松散耦合的方式进行通信,使得组件之间的交互......
  • [Bookmark]-C/C++
    C++类成员函数的函数指针sprintf与printf源码分析printf源码C语言实现简单的printf功能C中printf函数的实现原理TheGNUCLibraryglibc-printfC语言中的pow函数使用方法及注意事项,和常见报错原因,且分享实战中的使用注:仅用于记录使用过程中涉及的相关文档。......
  • SciTech-Python-编译Python的C/C++扩展的setup.py
    https://github.com/google-deepmind/tree/setup.py"""Setupforpippackage."""importos,platform,sys,sysconfig,shutil,subprocess,setuptoolsfromsetuptools.commandimportbuild_exthere=os.path.dirname(os.path.abspath......
  • C++零基础教程(什么是多态)
    (文章目录)前言本篇文章来给大家讲解一下C++中的多态,学习多态是了解C++特性必不可少的。一、多态的概念多态(Polymorphism)是面向对象编程中一个重要的概念,它允许基于对象的实际类型来调用相应的方法,以实现更灵活和可扩展的代码。在C++中,多态通常通过虚函数(VirtualFunction)和......
  • C++ 内联函数
    @TOC前言内联函数(InlineFunctions)是C++中一个重要的编程概念,它允许开发者在代码中使用一种特殊的方式来声明和定义函数,以提高程序的性能和可维护性。本文将详细讨论C++中的内联函数,包括如何定义、为何使用、以及其潜在优缺点。1.内联函数的基本概念内联函数是一种特殊的C++函数,通......
  • C++(引用符号&、访问内存地址&)
    在C++中,引用符号&和访问内存地址的&运算符有不同的用途和含义。引用符号&:创建引用使用&符号可以创建引用,即给一个变量起一个别名。引用是一个别名,它与原变量共享相同的内存地址。引用在声明时必须初始化,并且一旦初始化后,不能再引用其他变量。intx=10;int&ref......