Qt之容器类

一、容器类的概述

  Qt提供了多个基于模板的容器类,这些容器类可以用于存储指定类型的数据项,Qt的容器类比标准模板库(STL)中的容器类更轻巧、安全和易于使用。这些容器类是隐式共享和可重入的,而且它们进行了速度和存储优化,因此可以减少可执行文件的大小,此外,它们还是现场安全的,也就是说它们作为只读容器时可被多个线程访问。Qt的容器分为顺序容器和关联容器,容器迭代用于遍历容器里的数据项,Qt还提供了foreach宏用于遍历容器内的所有数据项。

二、顺序容器类

Qt的顺序容器类有QList、QLinkedList、QVector、QStack和QQueue

1.QList容器

QList 是 Qt 中的容器类,用于存储和管理元素的动态数组。它提供了高效的动态大小调整功能,支持插入、删除、查找和遍历元素。

以下是 QList 容器的介绍和使用示例:

  • QList 是一个模板类,可以存储任意类型的元素。
  • QList 支持在列表的任意位置插入、删除和访问元素,具有高效的动态大小调整功能。
  • 它提供了丰富的方法和操作,如迭代、搜索、排序、拼接等,以方便地操作列表中的元素。
  • QList 与标准 C++ 容器 std::vector 类似,但具有 Qt 特有的优化和功能。

(1).创建一个QList并添加元素

QList<QString> myList;
myList.append("Apple");
myList.append("Banana");
myList.append("Cherry");

(2).查找元素

int iIndex = myList.indexOf("Apple");
if (iIndex != -1) {
    qDebug() << "Found at index:" << iIndex;
} else {
    qDebug() << "not found";
}

(3).插入和删除元素

myList.insert(1, "Orange");
myList.removeAt(2);
myList.removeOne("Cherry");

(4).遍历容器元素

//使用at()函数遍历元素
for (int i = 0; i < myList.size(); i++) {
     //qDebug() << myList[i];
     qDebug() << myList.at(i);
}

//使用迭代器遍历元素
QList<QString>::iterator it;
for (it = myList.begin(); it != myList.end(); ++it) {
     qDebug() << *it;
}

//使用range-based for 循环遍历元素(C++11及更高版本)
for (const QString &item : myList) {
     qDebug() << item;
}

QList容器的优点:

  • 动态大小调整:QList 具有动态大小调整的能力,可以轻松地添加和删除元素,而不必担心手动分配或释放内存。

  • 高效的插入和删除:QList 对于在中间或开头插入或删除元素非常高效,因为它内部使用链表结构来维护元素。

  • 多种操作方法:QList 提供了丰富的操作方法,如迭代、搜索、排序、拼接等,方便进行元素的各种操作。

  • 容纳任意数据类型:QList 是一个模板类,可以存储任何数据类型的元素。

  • Qt 信号和槽机制:QList 在与 Qt 的信号和槽机制结合使用时非常有用,用于在数据模型中存储和管理数据,以便在界面上进行更新和显示。

QList容器的缺点:

  • 随机访问性能较差:相对于数组,QList 在随机访问元素时性能较差。如果需要频繁随机访问元素,QVector 可能更适合。

  • 额外的内存开销:QList 内部使用链表来实现元素的插入和删除,这会导致一些额外的内存开销,包括指向下一个元素的指针。

  • 不支持下标越界检查:与 std::vector 不同,QList 不会在访问超出范围的元素时抛出异常。这意味着在访问元素之前,需要自行确保索引不会越界。

  • 不支持排序时的稳定性:QList 在排序时不保证元素的相对顺序,因此在需要稳定排序的情况下,可能需要额外的工作。

总的来说,QList 在需要高效插入和删除元素以及在动态数据集中进行操作时非常有用。它适合用于管理不需要频繁随机访问的数据,特别是与 Qt 框架结合使用时。但在需要频繁随机访问的情况下,可能需要考虑使用 QVectorstd::vector 等支持连续存储的容器。  

2.QLinkedList容器

QLinkedList 是 Qt 中的容器类,它是双向链表,用于存储和管理元素的动态数据结构。双向链表是一种数据结构,其中每个元素都包含指向前一个和后一个元素的指针,这使得插入和删除操作非常高效。

以下是 QLinkedList 容器的介绍和使用示例:

特点和介绍:

  • QLinkedList 是一个模板类,可以存储任何类型的元素。
  • 它支持在列表的任意位置插入、删除和访问元素,具有高效的动态大小调整功能。
  • QLinkedList 内部使用链表结构,因此插入和删除元素的性能通常比数组高效,尤其是在中间或开头插入或删除元素时。
#include <QCoreApplication>
#include <QDebug>
#include <QLinkedList>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 QLinkedList 并添加元素
    QLinkedList<QString> myLinkedList;
    myLinkedList << "Apple" << "Banana" << "Cherry";

    // 使用迭代器遍历元素
    QLinkedList<QString>::iterator it;
    for (it = myLinkedList.begin(); it != myLinkedList.end(); ++it) {
        qDebug() << *it;
    }

    // 使用 range-based for 循环遍历元素(C++11 及更高版本)
    for (const QString &item : myLinkedList) {
        qDebug() << item;
    }

    // 插入和删除元素
    QLinkedList<QString>::iterator found = myLinkedList.begin();
    myLinkedList.insert(++found, "Orange"); // 在 "Apple" 后插入 "Orange"
    myLinkedList.removeOne("Cherry");

    // 输出列表
    for (const QString &item : myLinkedList) {
        qDebug() << item;
    }

    return a.exec();
}

QLinkedList容器优点:

  • 高效的插入和删除:QLinkedList 在中间或开头插入或删除元素时非常高效,因为它内部使用双向链表,只需要更新相邻元素的指针。这使得插入和删除操作比数组高效。

  • 动态大小调整:与 QList 一样,QLinkedList 具有动态大小调整的能力,可以轻松添加和删除元素,而不必担心手动分配或释放内存。

  • 内存效率:相对于数组,QLinkedList 不需要在内存中保留一段连续的存储空间,因此它对内存的利用更加高效。这对于大型数据集的元素插入和删除操作非常有利。

QLinkedList容器缺点:

  • 随机访问性能较差:相对于数组,QLinkedList 在随机访问元素时性能较差。如果需要频繁随机访问元素,QVectorQList 可能更适合。

  • 额外的内存开销:虽然 QLinkedList 在内存利用方面较为高效,但它需要额外的内存来存储链表节点的指针,因此可能会导致一些额外的内存开销。

  • 不支持下标访问:与数组不同,QLinkedList 不支持使用下标来访问元素。访问元素需要使用迭代器或遍历整个链表。

  • 不支持排序时的稳定性:QLinkedList 在排序时不保证元素的相对顺序,因此在需要稳定排序的情况下,可能需要额外的工作。

总的来说,QLinkedList 在需要频繁插入和删除元素、不需要随机访问元素、并且对内存效率有一定要求的情况下非常有用。但在需要频繁随机访问元素的情况下,可能需要考虑使用 QVectorQList 等支持连续存储的容器。选择容器类时,需根据具体需求和性能要求来权衡。

3.QVector容器

QVector 它是动态数组,用于存储和管理元素。与 QLinkedList 不同,QVector 在内部使用连续的内存块来存储元素,因此对于需要频繁随机访问元素的情况,QVector 是一个更合适的选择。

以下是 QVector 容器的介绍和使用示例:

  • QVector 是一个模板类,可以存储任何类型的元素。
  • 它支持在数组的任意位置插入、删除和访问元素,具有高效的动态大小调整功能。
  • QVector 内部使用连续的内存块来存储元素,这使得随机访问元素的性能非常高。
#include <QCoreApplication>
#include <QDebug>
#include <QVector>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 QVector 并添加元素
    QVector<QString> myVector;
    myVector.append("Apple");
    myVector.append("Banana");
    myVector.append("Cherry");

    //使用下班遍历元素
    for (int i = 0; i < myVector.size(); i++) {
        //qDebug() << myVector[i];
        qDebug() << myVector.at(i);
    }

    // 使用迭代器遍历元素
    QVector<QString>::iterator it;
    for (it = myVector.begin(); it != myVector.end(); ++it) {
        qDebug() << *it;
    }

    // 使用 range-based for 循环遍历元素(C++11 及更高版本)
    for (const QString &item : myVector) {
        qDebug() << item;
    }

    // 查找元素
    int index = myVector.indexOf("Banana");
    if (index != -1) {
        qDebug() << "Found at index:" << index;
    } else {
        qDebug() << "Not found";
    }

    // 插入和删除元素
    myVector.insert(1, "Orange");
    myVector.removeOne("Cherry");

    for (const QString &item : myVector) {
        qDebug() << item;
    }

    return a.exec();
}

QVector的优点:

  • 高效的随机访问:QVector 在随机访问元素时非常高效,因为它使用连续的内存块存储元素。这使得通过索引访问元素的性能非常好。

  • 动态大小调整:与 QListQLinkedList 类似,QVector 具有动态大小调整的能力,可以轻松添加和删除元素,而不必担心手动分配或释放内存。

  • 内存效率:相对于 QLinkedListQVector 的内存效率通常更高,因为它不需要额外的链表节点指针。

  • 支持标准算法:QVector 支持标准算法和容器操作,如排序、查找、拼接等。

QVector的缺点:

  • 插入和删除性能相对较差:与 QLinkedListQList 不同,QVector 在中间插入或删除元素时的性能较差,因为它需要将后续元素向后移动。如果需要频繁的插入和删除操作,QListQLinkedList 可能更适合。

  • 额外的内存开销:QVector 需要连续的内存块来存储元素,这可能导致额外的内存开销,尤其是在元素的数量发生变化时。

  • 不支持排序时的稳定性:与 QLinkedList 不同,QVector 在排序时不保证元素的相对顺序,因此在需要稳定排序的情况下,可能需要额外的工作。

总的来说,QVector 在需要高效随机访问元素的情况下非常有用,但在需要频繁插入和删除元素的情况下性能相对较差。根据具体需求,可以选择使用 QVectorQLinkedListQList 中的其中一个容器类,或者根据应用程序的特定需求来选择适当的容器类。

4.QStack容器

QStack 它是一个堆栈(stack)容器,用于存储元素,并遵循后进先出(LIFO,Last In, First Out)的原则。这意味着最后插入的元素将首先被弹出。

以下是 QStack 容器的介绍和使用示例:

  • QStack 是一个模板类,可以存储任何类型的元素。
  • 它支持将元素压入堆栈顶部(push)和从堆栈顶部弹出元素(pop)。
  • QStack 提供了一种简单的方式来实现后进先出的数据结构。
#include <QCoreApplication>
#include <QDebug>
#include <QStack>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 QStack 并添加元素
    QStack<QString> myStack;
    myStack.push("Apple");
    myStack.push("Banana");
    myStack.push("Cherry");

    // 弹出并输出堆栈元素
    while (!myStack.isEmpty()) {
        QString top = myStack.pop();
        qDebug() << top;
    }

    return a.exec();
}

5.QQueue容器

QQueue 它是一个队列(queue)容器,用于存储元素,并遵循先进先出(FIFO,First In, First Out)的原则。这意味着最先插入的元素将首先被弹出。

以下是 QQueue 容器的介绍和使用示例: 

#include <QCoreApplication>
#include <QDebug>
#include <QQueue>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 QQueue 并添加元素
    QQueue<QString> myQueue;
    myQueue.enqueue("Apple");
    myQueue.enqueue("Banana");
    myQueue.enqueue("Cherry");

    // 弹出并输出队列元素
    while (!myQueue.isEmpty()) {
        QString front = myQueue.dequeue();
        qDebug() << front;
    }

    return a.exec();
}

三、关联容器类  

Qt提供的关联容器有QMap、QMultiMap、QHash、QMultiHash和QSet,QMultiMap和QMultiHash支持一个键关联多个值,QHash和QMultiHash类使用散列(Hash)函数进行查找,查找速度更快。

1.QSet容器

QSet是基于散列表的集合模板类,它存储数据的顺序是不定的,查找值的速度非常快,QSet<T>内部就是用QHash实现的。它仅存不重复的元素,因此不允许重复值的存在。

#include <QCoreApplication>
#include <QDebug>
#include <QSet>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 QSet 并添加元素
    QSet<QString> mySet;
    mySet.insert("Apple");
    mySet.insert("Banana");
    mySet.insert("Cherry");

    // 查找元素
    if (mySet.contains("Banana")) {
        qDebug() << "Banana is in the set.";
    } else {
        qDebug() << "Banana is not in the set.";
    }

    // 添加重复元素(不会重复存储)
    mySet.insert("Banana");

    // 删除元素
    mySet.remove("Cherry");

    // 遍历集合
    QSet<QString>::iterator it;
    for (it = mySet.begin(); it != mySet.end(); ++it) {
        qDebug() << *it;
    }

    // 使用范围迭代遍历集合(C++11 及更高版本)
    for (const QString &item : mySet) {
        qDebug() << item;
    }

    return a.exec();
}

2.QMap容器

QMap<Key, T>提供一个字典(关联数组),一个键映射到一个值,QMap存储数据是按照键的顺序,它提供了键值对的存储和管理,其中键唯一,每个键应对一个值,如果不在乎存储顺序,使用QHash会更快。

#include <QCoreApplication>
#include <QDebug>
#include <QMap>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 QMap 并添加键值对
    QMap<QString, int> myMap;
    myMap["Apple"] = 5;
    myMap["Banana"] = 3;
    myMap["Cherry"] = 7;
    myMap.insert("Orange", 10);

    // 查找键值对
    if (myMap.contains("Banana")) {
        int value = myMap["Banana"];
        qDebug() << "Banana count: " << value;
    } else {
        qDebug() << "Banana not found.";
    }
    
    //表示如果在map里找到键"Banana"就返回关联的值,否则就返回指定的缺省值-1
    //int value = myMap.value("Bananas", -1);

    // 遍历键值对
    QMap<QString, int>::iterator it;
    for (it = myMap.begin(); it != myMap.end(); ++it) {
        qDebug() << it.key() << ": " << it.value();
    }

    // 使用范围迭代遍历键值对(C++11 及更高版本)
    for (const QString &key : myMap.keys()) {
        int value = myMap.value(key);
        qDebug() << key << ": " << value;
    }

    return a.exec();
}

3.QMultiMap容器

QMultiMap是QMap的子类,是用于处理多值映射的便利类,多值映射就是一个键可以对应多个值,QMap正常情况下不允许多值映射,除非使用QMap::insterMulti()添加键值对。QMultiMap是QMap的子类,所以QMap的大多数函数在QMultiMap都是可用的,但是有几个特殊的,QMultiMap::instert()等效于QMap::insertMulti(),QMultiMap::replace()等效于QMap::insert()。

#include <QCoreApplication>
#include <QDebug>
#include <QMultiMap>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 QMultiMap 并添加键值对
    QMultiMap<QString, int> myMultiMap;
    myMultiMap.insert("Apple", 5);
    myMultiMap.insert("Banana", 3);
    myMultiMap.insert("Cherry", 7);
    myMultiMap.insert("Apple", 10); // 添加重复的键

    // 查找键值对
    if (myMultiMap.contains("Apple")) {
        QList<int> values = myMultiMap.values("Apple");
        qDebug() << "Apple counts:";
        for (int value : values) {
            qDebug() << value;
        }
    } else {
        qDebug() << "Apple not found.";
    }

    // 遍历键值对
    QMultiMap<QString, int>::iterator it;
    for (it = myMultiMap.begin(); it != myMultiMap.end(); ++it) {
        qDebug() << it.key() << ": " << it.value();
    }

    // 使用范围迭代遍历键值对(C++11 及更高版本)
    for (const QString &key : myMultiMap.uniqueKeys()) {
        QList<int> values = myMultiMap.values(key);
        qDebug() << key << " counts:";
        for (int value : values) {
            qDebug() << value;
        }
    }

    return a.exec();
}

4.QHash容器

QHash是基于散列来实现字典功能的模板,QHash<QKey, T>存储的键值对具有非常快的查找速度,QHash与QMap的功能和用法相似,区别在于以下几点:

  • QHash比QMap的查找速度快。
  • 在QMap上遍历,数据项是按照键排序的,而QHash的数据项是任意顺序的。
#include <QCoreApplication>
#include <QDebug>
#include <QHash>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 QHash 并添加键值对
    QHash<QString, int> myHash;
    myHash.insert("Apple", 5);
    myHash.insert("Banana", 3);
    myHash.insert("Cherry", 7);

    // 查找键值对
    if (myHash.contains("Banana")) {
        int value = myHash.value("Banana");
        qDebug() << "Banana count: " << value;
    } else {
        qDebug() << "Banana not found.";
    }

    // 遍历键值对
    QHash<QString, int>::iterator it;
    for (it = myHash.begin(); it != myHash.end(); ++it) {
        qDebug() << it.key() << ": " << it.value();
    }

    // 使用范围迭代遍历键值对(C++11 及更高版本)
    for (const QString &key : myHash.keys()) {
        int value = myHash.value(key);
        qDebug() << key << ": " << value;
    }

    return a.exec();
}

5.QMultiHash容器

QMultiHash是QHash的子类,是用于处理多值映射的便利类,其用法与QMultiMap类似。

#include <QCoreApplication>
#include <QDebug>
#include <QMultiHash>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 QMultiHash 并添加键值对
    QMultiHash<QString, int> myMultiHash;
    myMultiHash.insert("Apple", 5);
    myMultiHash.insert("Banana", 3);
    myMultiHash.insert("Cherry", 7);
    myMultiHash.insert("Apple", 10); // 添加重复的键

    // 查找键值对
    if (myMultiHash.contains("Apple")) {
        QList<int> values = myMultiHash.values("Apple");
        qDebug() << "Apple counts:";
        for (int value : values) {
            qDebug() << value;
        }
    } else {
        qDebug() << "Apple not found.";
    }

    // 遍历键值对
    QMultiHash<QString, int>::iterator it;
    for (it = myMultiHash.begin(); it != myMultiHash.end(); ++it) {
        qDebug() << it.key() << ": " << it.value();
    }

    // 使用范围迭代遍历键值对(C++11 及更高版本)
    for (const QString &key : myMultiHash.keys()) {
        QList<int> values = myMultiHash.values(key);
        qDebug() << key << " counts:";
        for (int value : values) {
            qDebug() << value;
        }
    }

    return a.exec();
}

 

posted @ 2023-10-30 17:02  TechNomad  阅读(44)  评论(0编辑  收藏  举报