QVector应用大全

发布时间:2024年01月22日

一.概述

QVector是一个提供动态数组的模板类,它将其项存储在相邻内存中,并提供基于索引的快速访问操作。

QVector 本质就是封装好的数组,向量的相邻元素在内存里是连续存储的,可以用数组下标访问,其读取和修改元素的操作是非常快的

? QVector应该是我们实际开发中的默认首选序列式容器。QVector通常比QList性能更好,因为QVector总是将它的项按顺序存储在内存中;对于QList来说,将在堆上分配它的项,除非sizeof(T) <= sizeof(void*)并且T已经使用Q_DECLARE_TYPEINFO声明为Q_MOVABLE_TYPE或Q_PRIMITIVE_TYPE。

注意:QVector和QVarLengthArray都保证了c兼容的数组布局。QList没有,如果的应用程序必须与C API接口,这可能很重要。

二.程序示例

1.包含头文件 #include <QVector>

2.声明初始化

下面是一个存储整数的QVector和存储QString的QVector的例子:

??QVector<int> integerVector;

??QVector<QString> stringVector;

通常,vector是用初始大小创建的。

例如,下面的代码构造了一个包含200个元素的QVector:

QVector<QString> vector(200);

元素会自动用默认构造的值初始化(如果是int、double之类的话就是 0, QString就是空字符串)。如果你想用不同的值初始化vector,将该值作为第二个参数传递给构造函数:

QVector<QString> vector(200, "Pass");

还可以在任何时候调用 fill() 来用值填充 QVector:

??QVector<QString> vector(3);

??vector.fill("Yes");

??// vector: ["Yes", "Yes", "Yes"]

??vector.fill("hi", 5);

??// vector: ["hi", "hi", "hi", "hi", "hi"]

3.获取元素和链表信息

(1)使用at()成员函数访问QVector中的数据

const T &QVector::at(int i) const

例如:

for (int i = 0; i < vector.size(); ++i) {

????if (vector.at(i) == "iriczhao")

????????cout << "iriczhao position :" << i << Qt::endl;

}

(2)如果你想找到一个向量中某个特定值的所有出现情况,可以使用indexOf()或lastIndexOf()。 前者从给定的索引位置开始向前搜索,后者向后搜索。如果找到匹配项,两者都会返回匹配项的索引;否则,返回-1。例如:

??int i = vector.indexOf("Harumi");

??if (i != -1)

??????cout << "First occurrence of Harumi is at position " << i << Qt::endl;

也可以用 back() 和 front() 或者 last() 和 first() 获取首尾的值。

4.QVector常用API:

常用获取QVector 的属性:

contains():看QVector 是否包含特定值

count():获取某个元素在 QVector 里面的个数。

isEmpty():是不是空 向量

startsWith():是不是以某个元素开头

QVector提供了添加、移动和删除项的基本函数:

insert()、replace()、remove()、prepend()、append()。

?

5.迭代器:

遍历QVector 中的元素(Iterators: Traversing Elements in QVector)

QVector是Qt库中的一个容器类,用于存储动态数组。要遍历QVector中的元素,可以使用迭代器。迭代器提供了访问容器中元素的方法,并允许在容器内部导航。

以下是遍历QVector中元素的不同方法:

常规索引遍历

QVector<int> vector = {1, 2, 3, 4, 5};

for (int i = 0; i < vector.size(); ++i) {

????qDebug() << vector.at(i);

}

基于范围的for循环(C++11及以上)

QVector<int> vector = {1, 2, 3, 4, 5};

for (const int &value : vector) {

????qDebug() << value;

}

使用STL样式迭代器

QVector<int> vector = {1, 2, 3, 4, 5};

QVector<int>::iterator it;

for (it = vector.begin(); it != vector.end(); ++it) {

????qDebug() << *it;

}

使用Java样式迭代器

QVector<int> vector = {1, 2, 3, 4, 5};

QVectorIterator<int> it(vector);

while (it.hasNext()) {

????qDebug() << it.next();

}

使用const迭代器(只读访问)

QVector<int> vector = {1, 2, 3, 4, 5};

QVector<int>::const_iterator cit;

for (cit = vector.constBegin(); cit != vector.constEnd(); ++cit) {

????qDebug() << *cit;

}

以上是遍历QVector中元素的不同方法。根据需要和编程风格,可以选择任何一种方法来遍历QVector中的元素。在只读访问情况下,建议使用const迭代器,因为它提供了更好的类型安全和性能。

三.QVector原理与应用注意点

1.QVector 的底层实现与内存管理(Underlying Implementation and Memory Management of QVector)

QVector 是 Qt 框架中提供的一个动态数组容器,它以连续的内存空间存储元素。在本节中,我们将深入了解 QVector 的底层实现和内存管理。

底层实现:QVector 的底层实现基于动态数组。在内存中,QVector 的元素是连续存储的。这使得访问和遍历元素具有较高的效率。同时,QVector 支持 O(1) 复杂度的随机访问。在实际应用中,QVector 适用于对访问速度要求较高的场景。

内存分配:QVector 在内存管理上采用预分配策略。当向 QVector 中添加元素时,如果当前内存空间不足以容纳新元素,QVector 会重新分配一块更大的内存空间,并将原有元素复制到新的内存空间。为了减少内存分配和复制操作的开销,QVector 通常会预留一定的额外空间。这意味着 QVector 的实际容量(capacity)可能大于当前存储元素的数量(size)。

内存管理策略:QVector 采用一种称为“阶段性增长”的内存管理策略。在容器扩容时,QVector 会按照一定比例增加其容量。这种策略旨在在提高访问速度和降低内存碎片之间取得平衡。

内存释放:当从 QVector 中删除元素时,QVector 通常不会立即释放内存。这是为了避免频繁的内存分配和释放操作。然而,在某些情况下,可能需要手动调整 QVector 的容量。此时,可以使用 squeeze() 函数来释放未使用的内存空间,或者使用 reserve() 函数来预留一定的内存空间。

通过了解 QVector 的底层实现和内存管理策略,我们可以更好地利用 QVector 容器,优化程序性能。在实际开发中,我们应根据需求选择合适的容器类型,并在必要时调整容器的内存策略。

2.QVector的优缺点

QVector 是 Qt 提供的一个动态数组类,类似于 C++ 的 std::vector。它具有许多优点,但也存在一些缺点。以下列出了 QVector 的优缺点:

优点:

随机访问:QVector 提供了快速的随机访问,时间复杂度为 O(1),因此可以方便地访问和修改任意位置的元素。

空间效率:QVector 在内存中以连续的方式存储元素,这有助于减少内存碎片和提高空间利用率。此外,连续存储还有利于 CPU 缓存友好性,从而提高程序性能。

自动扩容:当 QVector 容量不足以存储新元素时,它会自动分配更多的内存并扩大容量。这使得使用 QVector 时无需担心内存管理问题。

API 丰富:QVector 提供了丰富的 API,如 append、prepend、insert、remove 等,使得对 QVector 的操作非常方便。

与 Qt 框架的兼容性:QVector 与 Qt 框架的其他部分紧密集成,使用 QVector 可以更好地保持代码风格的一致性,减少与 Qt 其他组件之间的兼容性问题。

缺点:

插入和删除性能:在 QVector 的头部插入或删除元素,以及在中间位置插入或删除元素时,性能较差,因为需要移动其余元素以填补空位或腾出空间。在这种情况下,时间复杂度为 O(n)。

预分配内存策略:QVector 在扩容时采用的是预分配内存策略,这意味着 QVector 的实际分配的内存大小可能大于实际使用的内存。在内存非常紧张的情况下,这可能会导致资源的浪费。

不支持节点式存储:与 QLinkedList 等链表结构相比,QVector 不支持节点式存储,因此在需要频繁进行插入和删除操作的场景下,可能不如链表结构高效。

综上所述,QVector 适合用于需要快速随机访问、空间效率较高的场景。然而,在需要频繁插入和删除元素的场景中,可能需要考虑其他数据结构,如 QLinkedList 或 QList。在选择合适的数据结构时,需要根据具体的应用场景和需求进行权衡。

3.QVector 的性能优化

QVector 是 Qt 中的一个动态数组容器,具有高性能且易于使用的特点。它在一些应用场景中,尤其是需要进行大量连续内存访问的操作时,性能优于 QList。以下是一些建议,帮助您在使用 QVector 时进一步优化性能:

预分配内存:QVector 提供了 reserve() 函数,允许您预先分配指定数量的内存。这可以减少多次重新分配和复制内存的开销,从而提高性能。尽量在已知最终大小的情况下使用此功能。

QVector<int> vector;

vector.reserve(1000); // 为 1000 个元素预留空间

使用 const_iterator:在只需要读取 QVector 中的数据,而不需要修改它们时,使用 const_iterator 可以提高性能。const_iterator 保证了数据不会被意外修改,同时可能允许编译器进行额外的优化。

QVector<int>::const_iterator iter;

for (iter = vector.constBegin(); iter != vector.constEnd(); ++iter) {

????// 处理 *iter,但不修改它

}

尽量避免频繁的插入和删除操作:尽管 QVector 提供了插入和删除元素的功能,但这些操作可能会导致内存移动和重新分配,从而影响性能。如果可能,请考虑在 QVector 的末尾添加元素,或使用其他适用于这些操作的容器,如 QList 或 QLinkedList。

选择适当的数据类型:在 QVector 中存储轻量级数据类型(如基本类型或较小的自定义类型)可以提高性能。如果需要存储大型对象,可以考虑使用指针或智能指针(如 QSharedPointer)来避免不必要的内存复制。

使用 C++11 范围 for 循环:C++11 引入了范围 for 循环,可以简化对 QVector 的遍历,并有助于提高性能。例如:

QVector<int> vector = {1, 2, 3, 4, 5};

for (const auto &value : vector) {

????// 处理 value

}

利用 Qt 的算法:Qt 提供了一系列基于 STL 的算法,如 qSort()、qFind() 等。它们针对 Qt 容器进行了优化,可以在某些情况下提高性能。

通过遵循上述建议,您可以在使用 QVector 时实现更高的性能。请注意,根据具体应用场景和需求,可能需要权衡不同容器类之间的优缺点。在选择合适的容器类时,要考虑内存使用、性能、易用性等多方面因素

4.使用QVector可能遇到的问题和解决方案

使用 QVector 时,可能会遇到以下问题。这里我们针对这些问题提供一些建议和解决方案:

内存占用过大:

问题:当 QVector 预分配的内存大小远大于实际需要时,可能会导致内存占用过大。

解决方案:可以使用 squeeze() 函数释放未使用的内存,将 QVector 的容量调整为实际大小。此外,合理使用 reserve() 函数预分配内存,以减少内存浪费。

非线程安全:

问题:QVector 是非线程安全的容器类,这意味着在多线程环境下对 QVector 的访问可能会导致竞争条件和数据不一致。

解决方案:在多线程环境下使用 QVector 时,确保对共享数据的访问使用互斥锁(QMutex)或其他同步机制进行保护。

性能下降:

问题:对 QVector 进行频繁的插入和删除操作,尤其是在中间位置,可能导致性能下降。

解决方案:如果需要频繁执行插入和删除操作,可以考虑使用其他容器类,如 QLinkedList。在适当的情况下,使用 append() 和 prepend() 函数在 QVector 的开头和结尾插入元素,以减少性能开销。

扩展限制:

问题:QVector 的大小受到内存限制,当处理大规模数据时,可能会遇到扩展问题。

解决方案:针对大规模数据,可以考虑使用其他数据结构,如树状结构、哈希表等,或者将数据拆分为多个 QVector。

元素初始化:

问题:QVector 默认会初始化其所有元素,这可能会导致性能下降和不必要的资源浪费。

解决方案:可以使用 QVector::fromRawData() 函数构建一个不拥有数据的 QVector 实例。此方法可以跳过元素初始化,但要注意数据所有权和生命周期的管理。

通过以上解决方案,可以有效应对在使用 QVector 时可能遇到的问题。在实际项目中,确保对 QVector 的特性和局限有充分了解,以便做出合适的决策和优化。

5.QVector 的应用场景

QVector是Qt框架中的一个动态数组类,用于存储相同类型的元素。QVector内部使用连续内存存储元素,提供了随机访问、插入和删除等操作。以下是一些典型的QVector应用场景:

随机访问:由于QVector内部使用连续内存存储元素,它提供了快速的随机访问能力。这使得QVector在需要频繁访问数据集中任意元素的场景下非常适用。

动态数组:QVector可以根据需要自动调整大小,这使得它在处理不确定大小的数据集时非常有用。在需要动态调整数组大小的场景下,QVector比固定大小的数组更加灵活。

高效的插入和删除:QVector在尾部插入和删除元素非常高效。这使得QVector在需要频繁添加或删除尾部元素的场景下非常合适。

缓存和缓冲区:QVector可以用作缓存或缓冲区,用于存储从外部数据源(如文件、网络等)接收到的数据。这可以提高数据处理速度,避免频繁访问外部数据源。

图形和数据可视化:在处理图形和数据可视化任务时,QVector可以用于存储点、颜色、纹理坐标等数据。它可以与Qt的绘图和数据可视化工具一起使用,如QPainter和QCustomPlot。

6.QVector 的性能分析:查找、插入与删除操作

QVector是Qt框架中的一个动态数组类,用于存储相同类型的元素。QVector内部使用连续内存空间来存储元素,这使得QVector在查找、插入和删除操作上的性能与标准库中的std::vector相似。以下是QVector在这些操作上的性能分析:

查找操作: 对于QVector来说,随机访问的时间复杂度为O(1)。这意味着,访问QVector中的任意元素都可以在常数时间内完成。由于QVector采用连续内存空间存储元素,其随机访问速度通常优于QList。

插入操作:

在QVector的尾部插入元素具有较高的性能,平均时间复杂度为O(1)。这是因为QVector会预分配一定的空间,避免了频繁的内存重新分配。然而,当QVector的预分配空间耗尽时,插入操作的时间复杂度可能上升至O(n),其中n为QVector的大小。

在QVector的头部或中间插入元素的性能较差,时间复杂度为O(n),其中n为QVector的大小。在这种情况下,插入元素需要移动大量现有元素以腾出空间。

删除操作:

从QVector的尾部删除元素具有较高的性能,时间复杂度为O(1)。这与尾部插入操作的原理相同。

从QVector的头部或中间删除元素的性能较差,时间复杂度为O(n),其中n为QVector的大小。在这种情况下,删除元素需要移动大量现有元素以填补空缺。

总之,QVector在查找操作方面具有很好的性能,尤其是随机访问。在插入和删除操作方面,QVector在尾部的性能较好,但在头部和中间的性能较差。根据具体需求,开发者可以选择QVector或其他容器类(如QList、QLinkedList等)来实现所需的功能。

文章来源:https://blog.csdn.net/xieliru/article/details/135757194
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。