C++ Qt 開発: 関連するコンテナ クラスの使用

プログラミングでデータ構造について話すとき、シーケンシャル コンテナは無視できない重要な概念です。シーケンシャル コンテナは、要素が追加された順序でデータを格納および取得するデータ構造です。データを整理および管理するためのシンプルかつ直感的な方法を提供し、プログラマーに柔軟性とパフォーマンスのバランスを提供します。

Qt は、データの管理と操作を便利にするための豊富なコンテナ クラスを提供します。これらのコンテナ クラスは、単純な動的配列から複雑なマップやコレクションまで、さまざまな用途に対応します。この章では、主に QMapQSetQHash などの連想コンテナについて学習します。取得. キーによる値の素早い検索を可能にする機能。

1.1 Qマップ

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 A複数値のマッピングを処理するために使用されるクラスのサブセット。つまり、従来の QMap は 1 対 1 の関係のみを持つことができますが、 QMultiMap は 1 対 1 の関係を実装できます。 Key は複数の Value に対応し、その逆も同様に 1 対多の関係を実現します。

要約すると、この 2 つの類似点と相違点がわかります。

Qマップ
  • 一意のキー: QMap の各キーは一意であり、重複したキーは許可されません。
  • キーの並べ替え: QMap の要素はキーの昇順で並べ替えられます。
  • 使用シナリオ: キーと値のペアを順序付けする必要があり、キーが一意である必要があるシナリオに適しています。
Qマルチマップ
  • 重複キーを許可する: QMultiMap には重複キーを含めることができます。つまり、複数のキーを同じ値にマッピングできます。
  • キーの並べ替え: QMultiMap の要素はキーの昇順で並べ替えられます。
  • 使用シナリオ: は、重複キーが許可され、キーと値のペアを順序付ける必要があるシナリオに適しています。
同じ点
  1. キーと値のペア: は、キーと値のペアを保存するために使用されるコンテナです。
  2. 順序: 要素はコンテナ内でキーの昇順に並べられます。
違い
  1. キーの一意性: QMap の各キーは一意ですが、QMultiMap では重複キーが許可されます。
  2. 使用シナリオ: QMap は一意のキーが必要な状況に適しており、QMultiMap は重複キーが許可されている状況に適しています。

以下に示すように、QMultiMap を使用して 1 対多のマッピング関係を実装する方法を示します。

#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 Qハッシュ

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) 2 つの QHash をマージし、other の要素を現在の QHash にマージします。
intersect(const QHash &other) 両方に共通の要素を保持し、QHash 他の要素を削除します。
subtract(const QHash &other) に共通する要素を現在の QHash から削除します。 other
toStdHash()定数 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();
}

ここで 1 つ説明する必要があります。QMap と同様に、QHash も使用できます。QMultiHash その操作QMultiMap一貫性を保つことと同じです。ここの読者は自分で試すことができます。

1.3 Qセット

QSet は、C++ 標準ライブラリの std::unordered_set に似た、Qt の順序なし連想コンテナです。主に要素の順序を気にせずに一意の値を保存するために使用されます。 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 成员进行升序排序。

おすすめ

転載: blog.csdn.net/lyshark_csdn/article/details/134910680