QT中的 容器(container)-大全

一、介绍

Qt库提供了一套通用的基于模板的容器类,可以用这些类存储指定类型的项。比如,你需要一个大小可变的QString的数组,则使用QVector<QString>。

这些容器类比STL(C++标准模板库)容器设计得更轻量、更安全并且更易于使用。如果对STL不熟悉,或者倾向于用“Qt的方式”,那么你可以使用这些类,而不去使用STL的类。(STL容器使用详见首页其他作品)

二、容器类

Qt提供了一些顺序容器:QList、QLinkedList、QVector、QStack和QQueue。因为这些容器中的数据都是一个接一个线性存储的,所以称为顺序容器。大多数时候,QList是最好的选择,虽然是用数组实现的,但在它的首尾添加元素都非常快。如果你需要一个链表(linked-list)就用QLinkedList;想要你的项在内存中连续存储,就使用QVector。QStack和QQueue(栈和队列)分别提供了后进先出(LIFO)和先进先出(FIFO)的机制。

Qt还提供了一些关联容器:QMap、QMultiMap、QHash、QMultiHash、QSet。因为这些容器存储的是<键,值>对,比如QMap<Key,T>,所以称为关联容器。其中“Multi”容器支持一个键对应多个值。“Hash”容器在有序集合上使用hash函数进行快速的查找,而没有用二叉搜索。

容器也可以嵌套使用,例如QMap<QString,QList<int> >,这里键的类型是QString,而值的类型是QList<int>,需要注意,在后面的“> >”符号之间要有一个 空格,不然编译器会将它当作“>>”操作符对待。

该代码运行环境为Windows,采用Mingw64编译器输出结果。

1. QList容器

QList是一个模板类,提供了一个列表。QList<T>实际上是一个T类型项目的指针数组,所以支持基于索引的访问,而且当项目的数目小于1000时,可以实现在列表中间进行快速的插入操作。

QList提供了很多方便的接口函数来操作列表中的项目,例如插入操作insert()、替换操作replace()、移除操作removeAt()、移动操作move()、交换操作swap()、在表尾添加项目append()、在表头添加项目prepend()、从列表中移除一项并获取这个项目takeAt()及相应的takeFirst()和takeLast()、获取一个项目的索引indexOf()、判断是否含有相应的项目contains()以及获取一个项目出现的次数count()等。

插入

#include "widget.h"#include <QApplication>
#include <QList>
#include <QMap>
#include <QSplitter>
#include <QVector2D>
#include <QVector>
#include <QtAlgorithms>
#include <QtCore>
#include <QtWidgets>void printList(QList<int>&li)
{for(auto it = li.begin();it != li.end();it++){qDebug()<< *it <<"=\t"<< &(*it);}
}int main(int argc, char* argv[])
{QCoreApplication a(argc, argv); //无GUI的窗口QList<int> li;//插入li.insert(li.begin(),1); //在迭代器开始位置插入1li.insert(0,2); //在0序号位置插入 2li.insert(4,100); //在4序号位置插入 100li.append(10); //追加元素10li.push_back(3); // 尾插li.push_front(3); // 头插li.push_back(1);li.push_back(1);li.push_back(1);li.push_back(1);li << 20 << 30<<40;//替换li.replace(0,200);printList(li);return a.exec();
}

运行结果如下,可以看出QList容器的元素地址分配十分规律,一次偏移8字节 ,存储的应该是指针(不确定)

其他操作

QList<int> li;//插入li << 20 << 30<<40<< 50<<60 <<30 ;//删除li.erase(li.begin());li.takeAt(0);//    li.takeLast();   // 删除最后一个元素//    li.takeFirst();  // 删除第一个元素//替换li.replace(3,200); // 3下标 为第四个//统计qDebug()<<"count(3) = "<<li.count(30); //统计元素出现的次数qDebug()<<"contains 50? = "<< li.contains(50);

 QVector容器

插入

插入和QList容器相比,insert方法插入  li.insert(4,100);  报错:不能够超出索引插入元素。

#include "widget.h"#include <QApplication>
#include <QList>
#include <QMap>
#include <QSplitter>
#include <QVector2D>
#include <QVector>
#include <QtAlgorithms>
#include <QtCore>
#include <QtWidgets>void printList(QVector<int>&li)
{for(auto it = li.begin();it != li.end();it++){qDebug()<< *it <<"=\t"<< &(*it);}
}
int main(int argc, char* argv[])
{QCoreApplication a(argc, argv); //无GUI的窗口QVector<int> li;//插入li.insert(li.begin(),1); //在迭代器开始位置插入1li.insert(0,2); //在0序号位置插入 2
//    li.insert(4,100); //在4序号位置插入 100li.append(10); //追加元素10li.push_back(3); // 尾插li.push_front(3); // 头插li.push_back(1);li.push_back(1);li.push_back(1);li.push_back(1);li << 20 << 30<<40;//替换li.replace(0,200);printList(li);return a.exec();
}

运行结果如下,可以看到内存直接分配的间隔为4字节,比QList小 ,存储的为int的大小

 

其他方法

比QList容器多个capacity 方法,类似与std::vector容器

QLinkedList

QLinkedList 的废弃:从 Qt 6.0 开始,QLinkedList 容器已被废弃并从 Qt 容器库中移除。Qt 团队推荐使用 std::list(C++ 标准库中的双向链表)作为替代

QLinkedList(Qt链表)是一个 C++ 标准库中的双向链表容器类,它是 Qt 框架中的一部分。Qt 框架是一个跨平台的应用程序开发框架,广泛应用于 GUI 和非 GUI 程序的开发。QLinkedList 提供了一个高效的数据结构,用于存储和管理元素的集合。

重要性:

动态大小:QLinkedList 的大小是动态的,可以根据需要轻松添加或删除元素。这使得它在处理具有不确定大小的数据集时非常有用。
双向遍历:与 QVector 和 QList 不同,QLinkedList 允许从头到尾以及从尾到头的双向遍历。这种遍历方式在某些场景下会非常有用。
高效的插入和删除操作:在链表的中间插入或删除元素的时间复杂度为 O(1)。这使得 QLinkedList 在需要频繁插入和删除元素的场景中,具有优势。
不需要连续内存:与 QVector 和 QList 相比,QLinkedList 的元素不需要存储在连续的内存空间中。这意味着在内存碎片化的情况下,QLinkedList 可能更容易分配内存。

QLinkedList 的性能优化

QLinkedList 是 Qt 提供的双向链表容器,适用于需要频繁插入和删除元素的场景。在某些情况下,使用 QLinkedList 可以获得更好的性能。以下是关于 QLinkedList 性能优化的一些建议:

适用场景选择:在需要频繁插入和删除元素的场景下,使用 QLinkedList 是合适的,因为它在这些操作上具有优秀的性能。然而,如果需要频繁地随机访问元素,QList 或 QVector 可能是更好的选择,因为它们提供更快的随机访问速度。
使用迭代器:QLinkedList 提供了迭代器接口,以高效地遍历链表。在需要遍历链表时,使用迭代器可以获得更好的性能。要注意的是,在遍历过程中插入或删除元素时,应使用迭代器的 insert() 和 remove() 函数,以保持链表的完整性。
减少内存分配次数:尽管 QLinkedList 在插入和删除元素时性能优越,但它的内存分配次数相对较多。为了提高性能,可以预先估计链表的大小,并通过 reserve() 函数预留相应的内存空间,以减少内存分配次数。
使用空间局部性:QLinkedList 的元素存储在非连续的内存地址中,这可能导致 CPU 缓存利用率降低。在可能的情况下,尝试让相邻的元素在逻辑上也相邻,以提高空间局部性。
避免频繁拷贝:链表的拷贝操作相对较慢。如果需要共享数据,可以考虑使用 QSharedPointer 进行引用计数,以避免频繁的拷贝操作。
总之,为了充分发挥 QLinkedList 的性能优势,开发者应在合适的场景下使用它,并采用迭代器、预留内存等方法进行优化。同时,也要注意避免在不适合的场景下使用 QLinkedList,以确保整体性能的最优化。

插入

容器的insert插入方法不能指定下标,需要迭代器,且没有replace方法。

template <typename T>
void printList(QLinkedList<T>&li)
{for(auto it = li.begin();it != li.end();it++){qDebug()<< *it <<"=\t"<< &(*it);}}int main(int argc, char* argv[])
{QCoreApplication a(argc, argv); //无GUI的窗口QLinkedList<int> li;//插入li.insert(li.begin(),1); //在迭代器开始位置插入1
//       li.insert(0,2); //在0序号位置插入 2
//       li.insert(4,100); //在4序号位置插入 100li.append(10); //追加元素10li.push_back(3); // 尾插li.push_front(3); // 头插li.push_back(1);li.push_back(1);li.push_back(1);li.push_back(1);li << 20 << 30<<40;//替换
//       li.replace(0,200);printList(li);a.exec();
}

结果如下,可以看到元素直接不是顺序存储的,是通过指针链接在一起的,两个相连元素之间大概相差32字节,(因为是双向链表,内存随机分配,每个节点应该包含了 int类型4字节和两个指针16字节,再加上内存偏移)

其他操作

    QLinkedList<int> li;//插入li << 20 << 30<<40<< 50<<60 <<30 ;//删除li.erase(li.begin());
//        li.takeAt(0);//    li.takeLast();   // 删除最后一个元素//    li.takeFirst();  // 删除第一个元素//替换//统计qDebug()<<"count(3) = "<<li.count(30); //统计元素出现的次数qDebug()<<"contains 50? = "<< li.contains(50);//访问元素li.back();li.front();QLinkedList<int>::iterator it = std::find(li.begin(),li.end(),30);if(it!= li.end()){qDebug() <<*it;}

QStack

QStack(Qt Stack)是一个来自于Qt框架的容器类,类似于C++标准库中的std::stack。QStack容器是一种后进先出(LIFO)的数据结构,即最后一个进入堆栈的元素将最先被移除。QStack继承了QVector,所以它拥有QVector的所有功能,同时提供了堆栈的特定操作。
由于QStack继承自QVector,因此它还具有QVector的所有成员函数,如append()、at()、capacity()、contains()、count()、data()、fill()、indexOf()、insert()、lastIndexOf()、mid()、prepend()、remove()、removeAll()、removeAt()、removeFirst()、removeLast()、replace()、reserve()、resize()、size()、squeeze()、startsWith()、swap()、takeAt()、takeFirst()、takeLast()、value()等。然而,在使用QStack时,最好坚持使用堆栈特定的接口,以保持代码的清晰性和可读性。
 

#include "widget.h"#include <QApplication>
#include <QList>
#include <QMap>
#include <QSplitter>
#include <QVector2D>
#include <QVector>
#include <QtAlgorithms>
#include <QtCore>
#include <QtWidgets>template <typename T>
void printList(QStack<T>&li)
{for(auto it = li.begin();it != li.end();it++){qDebug()<< *it <<"=\t"<< &(*it);}}int main(int argc, char* argv[])
{QCoreApplication a(argc, argv); //无GUI的窗口QStack<int>s;s.reserve(100); //提前分配内存s.size(); //获取数据大小s.capacity(); //查看容量大小s.push(2);s.push(3);s.push(4);s.push(5);s.insert(0,1);s.insert(1,4);//查看栈顶元素s.top();//弹出栈顶元素s.pop();printList(s);a.exec();
}

运行结果如下,栈是一种顺序存储的容器,每个元素直接相隔4字节大小。

其他用法

s.toList(); //转为QList容器s.toStdVector(); //转为std::vectorprintList(s);qDebug()<<"stack size = "<<sizeof(s);QList<int>l=s.toList();std::vector<int> v=s.toStdVector();printList(l);qDebug()<<"QStack  size = "<<sizeof(l);qDebug()<<"std::vector  size = "<<sizeof(v);v.push_back(10);qDebug()<<"std::vector  size = "<<sizeof(v);

这里补充下关于QStack容器大小的问题,stack容器里有5个int类型的容器,我们可能以为sizeof的大小的5*4 =20;但是这里却是8字节,转为STL中的容器,可以看到结果如下所示,这些容器的内部会有各自的实现。

QQueue容器

QQueue 是 Qt 库中的一个容器类,它表示一个双端队列(double-ended queue,简称 deque)。QQueue 提供了在队列两端进行高效插入和删除操作的功能。QQueue 继承自 QList,可以在首尾方便地添加和删除元素。下面是一些 QQueue 的使用场景:

任务队列:可以用 QQueue 来管理一个任务队列,将待处理的任务添加到队列中,然后依次处理并移除已完成的任务。这种场景下,可以将 QQueue 当作一个先进先出(FIFO)数据结构来使用。
消息队列:在多线程应用中,可以使用 QQueue 存储线程间通信的消息。主线程将消息添加到队列中,子线程从队列中取出消息并处理。这种场景下,需要确保对队列的访问是线程安全的,可以通过加锁等机制实现。
数据缓冲:在处理大量数据时,可以使用 QQueue 作为缓冲区,存储已经处理过的数据,以便在需要时能够快速访问。例如,在处理实时音频或视频数据时,可以将已处理的数据帧存入 QQueue 中,以备后续的播放或分析使用。
编程算法:QQueue 可以用于实现一些编程算法,如宽度优先搜索(BFS)等。通过将待处理的节点添加到队列中,可以保证算法的执行顺序。
事件处理:在事件驱动的程序中,可以使用 QQueue 存储待处理的事件。当事件发生时,将事件对象添加到队列中,然后逐个处理并删除队列中的事件。

比QVector容器多了enqueue插入元素的方法。

综上所述,QQueue作为一种实用的数据结构,广泛应用于不同领域的软件开发。了解QQueue的重要性和基本概念,将有助于开发者更好地利用这一工具解决实际问题。

QQueue的性能优化


  QQueue 是 Qt 容器类之一,它实现了一个先进先出(FIFO)的队列。QQueue 是 QList 的子类,因此它继承了 QList 的许多特性。为了优化 QQueue 的性能,可以采取以下几个方面的措施:利用 QList 的特性:QQueue 的底层实现基于 QList,所以可以利用 QList 的性能优势。QList 的内存分配策略使得在队列的头部和尾部插入和删除元素具有较高效率。因此,当使用 QQueue 时,尽量避免在队列中间进行插入和删除操作。
预分配内存:如果可以预估队列的最大大小,那么可以使用 QQueue::reserve() 函数预先分配内存。这将有助于减少内存分配和释放的开销,提高性能。
避免频繁的内存分配:在频繁地向队列添加和删除元素时,避免频繁的内存分配和释放。可以考虑使用对象池或其他内存管理技术来重用对象,从而提高性能。
使用 const 成员函数:在遍历队列或访问队列元素时,使用 const 成员函数(如 constFirst() 和 constLast())可以避免不必要的拷贝操作,提高性能。
考虑使用其他容器:在某些特定场景下,QQueue 可能不是性能最优的选择。例如,如果需要处理大量连续内存访问操作,可以考虑使用 QVector。同样,如果需要在列表中间频繁地插入和删除元素,QLinkedList 可能是更好的选择。根据实际需求选择合适的容器类,以实现最佳性能。
总之,在使用 QQueue 时,可以通过充分利用 QList 的特性、预分配内存、避免频繁的内存分配、使用 const 成员函数以及根据需求选择合适的容器类等方法来优化性能。

插入

#include "widget.h"#include <QApplication>
#include <QList>
#include <stack>
#include <queue>
#include <map>
#include <QMap>
#include <QSplitter>
#include <QVector2D>
#include <QVector>
#include <QtAlgorithms>
#include <QtCore>
#include <QtWidgets>
#include <vector>template <typename T>
void printList(QList<T>&li)
{for(auto it = li.begin();it != li.end();it++){qDebug()<< *it <<"=\t"<< &(*it);}}template <typename T>
void printList(QQueue<T>&li)
{for(auto it = li.begin();it != li.end();it++){qDebug()<< *it <<"=\t"<< &(*it);}}int main(int argc, char* argv[])
{QCoreApplication a(argc, argv); //无GUI的窗口QQueue<int>li;li.enqueue(2);li.enqueue(3);li.insert(0,1);li << 20 << 30<<40;//替换li.replace(0,200);qDebug()<<"head = "<<li.head();qDebug()<<"take = "<<li.takeAt(3); //删除元素返回元素值li.dequeue(); //出队列printList(li);a.exec();
}

可以看到 QQueue是一个顺序存储的容器,每个元素之间的间隔为8个字节同QList(继承关系)

​​​​​​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/178771.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

光伏电站开发流程

随着人们对可再生能源的关注度不断提高&#xff0c;光伏电站的开发流程也变得越来越重要。光伏电站是一种利用太阳能发电的设施&#xff0c;它可以有效地减少化石能源的消耗&#xff0c;同时也可以为环保事业做出贡献。 首先&#xff0c;要进行光伏电站的开发&#xff0c;需要选…

PWM 正玄波形 通过C语言生成

#include <stdio.h> #include <math.h> #include <stdint.h>#define SAMPLE_POINT_NUM (200) /* 需要生成的点的个数 */ #define SINE_MAX (255) /* sin 函数幅值 */ #define PI (3.14…

pytorch训练模型内存溢出

1、训练模型命令命令 如下所示是训练命名实体识别的命令&#xff0c;在win10系统下执行 activate pytorch cd F:\Python\github\ultralytics-main\submain\pytorch_bert_bilstm_crf_ner-main f: python main.py --bert_dir"../model_hub/chinese-bert-wwm-ext/" --…

TIME_WAIT状态TCP连接导致套接字无法重用实验

理论相关知识可以看一下《TIME_WAIT相关知识》。 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #include<errno.h> #include<syslog.h> #inc…

Echarts legend图例配置项 设置位置 显示隐藏

Echarts 官网完整配置项 https://echarts.apache.org/zh/option.html#legend 配置项 legend: { }设置图例为圆形 icon: circle,//设置图例为圆形设置图例位置 top: 20%//距离顶部百分之20//y:bottom 在底部显示设置图例 宽度 高度 itemWidth: 10,//设置图例宽度 itemHeight: …

每日一练【移动零】

一、题目描述 283. 移动零 - 力扣&#xff08;LeetCode&#xff09; 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 二、题目解析 可以…

Python中调用VisualStudio创建的DLL库

1、创建DLL 打开VisualStudio2022&#xff0c;创建新项目 动态链接库-下一步 设置项目名称、项目位置、创建 单击头文件、添加、新建项 选择.h、设置名称、添加 同样的在源文件新建项&#xff0c;创建 代码&#xff1a; test.h #pragma once#ifdef BUILD_TEST #define API_S…

unity3d NPC自动寻路不移动

烘焙的路面不能有间隔&#xff0c;调整地面重新烘焙

数据结构(超详细讲解!!)第二十五节 树与森林

1.树的存储结构 和线性表一样&#xff0c;树可以用顺序和链式两种存储结构。 树的顺序存储结构适合树中结点比较“满”的情况。根据树的非线性结构特点&#xff0c;常用链式存储方式来表示树。树常用的存储方法有&#xff1a;双亲表示法、孩子表示法和孩子兄弟表…

【Linux进阶之路】进程间通信

文章目录 一、原理二、方式1.管道1.1匿名管道1.1.1通信原理1.1.2接口使用 1.2命名管道 2.共享内存2.1原理2.2接口使用 3.消息队列原理 4.信号量引入原理 总结 一、原理 进程间的通信是什么&#xff1f;解释&#xff1a; 简单理解就是&#xff0c;不同进程之间进行数据的输入输出…

Typora+PicGo+Minio搭建博客图床

文章目录 TyporaPicGoMinio搭建博客图床前言什么是图床?为什么需要图床?准备工作一、Typora二、Picgo1. 下载Picgo2. 下载node.js3. 下载minio插件 三、服务器端配置1. 添加端口到安全组2. 使用Docker安装minio3. 配置minio image-20231127175530696四、minio插件配置五、Typ…

C++ day37 贪心算法 单调递增的数字 监控二叉树

题目1&#xff1a;738 单调递增的数字 题目链接&#xff1a;单调递增的数字 对题目的理解 返回小于或等于n的最大数字&#xff0c;且数字是单调递增&#xff08;单调递增数字的定义&#xff1a;每个相邻位上的数字满足x<y&#xff09; 贪心算法 注意本题的遍历顺序是从…

【带头学C++】----- 八、C++面向对象编程 ---- 8.1 面向对象编程概述

目录 8.1 面向对象编程概述 8.1.1 面向对象概念&#xff08;OOP&#xff09; 8.1.2 面向过程概念 8.2 :: 作用域运算符 8.3 命名空间namespace 8.3.1 C的命名空间 namespace 8.3.2 命名空间 namespace使用语法 1. 创建一个命名空间&#xff1a; 2. 命名空间只能在全局…

WIN10 x86环境部署ARM虚拟机(银河麒麟)

我们经常使用的是x86架构的cpu&#xff0c;而对于不同cpu架构的arm架构的操作系统&#xff0c;我们可以通过QEMU模拟器来进行模拟一个arm环境 1、部署前的准备 arm的镜像&#xff1a; 以此镜像为例&#xff1a;Kylin-Server-10-SP2-aarch64-Release-Build09-20210524.iso QE…

Co-DETR:DETRs与协同混合分配训练论文学习笔记

论文地址&#xff1a;https://arxiv.org/pdf/2211.12860.pdf 代码地址&#xff1a; GitHub - Sense-X/Co-DETR: [ICCV 2023] DETRs with Collaborative Hybrid Assignments Training 摘要 作者提出了一种新的协同混合任务训练方案&#xff0c;即Co-DETR&#xff0c;以从多种标…

人力资源管理后台 === 组织架构

目录 1.组织架构-树组件应用 2.组织架构-树组件自定义结构 3.组织架构-获取组织架构数据 4.组织架构-递归转化树形结构 5.组织架构-添加子部门-新建弹层组件 6.组织架构-添加子部门-表单结构 7.组织架构-添加子部门-表单基本校验 8.组织架构-添加子部门-表单业务校验 9…

什么是计算机病毒?

计算机病毒 1. 定义2. 计算机病毒的特点3. 计算机病毒的常见类型和攻击方式4. 如何防御计算机病毒 1. 定义 计算机病毒是计算机程序编制者在计算机程序中插入的破坏计算机功能或者破坏数据&#xff0c;影响计算机使用并且能够自我复制的一组计算机指令或程序代码。因其特点与生…

Redis面试题:分片集群相关问题

目录 面试官&#xff1a;redis的分片集群有什么作用 面试官&#xff1a;Redis分片集群中数据是怎么存储和读取的&#xff1f; 面试官&#xff1a;redis的分片集群有什么作用 候选人&#xff1a;分片集群主要解决的是&#xff0c;海量数据存储的问题&#xff0c;集群中有多个m…

0004Java程序设计-ssm基于微信小程序的校园第二课堂

文章目录 摘 要目录系统设计开发环境 编程技术交流、源码分享、模板分享、网课分享 企鹅&#x1f427;裙&#xff1a;776871563 摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。…

锐捷:下一代防火墙修改密码

一、背景 刚接到的任务&#xff0c;锐捷行业的一台下一代防火墙的管理密码和管理地址都忘记了&#xff0c;并且命令登陆也设置了密码&#xff0c;只能通过重置的方式来进行管理&#xff0c;配置了。 本案例是一台RG-WALL 1600-S3200。 二、配置思路 1、准备环境 2、收集设备软…