在C++初级开发阶段很少用到模板类,读书时接触到数组总有种熟悉的陌生感。工作后,许多同事也对模板类敬而远之,除了使用基本的Vector模板类之外,对其余STL一窍不通,本质上是对数据结构知识掌握的不足。了解数据结构,明白各种数据容器数据存取过程,却不熟稔具体代码的实现。借着对Qt的全面巩固,深入了解Qt和C++中的STL。
注:本文只记录一些常用的模板类及其功能接口,不考虑底层实现,主要用以区分各种数据结构添加与删除元素的不同之处。
常用模板类:
| Qt | C++ | |
| 动态数组 | QVector | vector |
| 栈 | QStack | stack |
| 队列 | QQueue | queue |
| 列表 | QList | list |
| 集合 | QSet | std::set |
| 关联容器类 | QMap | std::map |
| 哈希表 | QHash | std::unordered_map |
一、动态数组(QVector和std::vector)
QVector和std::vector的内存布局功能特性类似。两者不同之处除了面向的开发对象不同之外,QVector还支持隐式共享,即拷贝QVector仅增加引用计数,实际数据修改时才触发深拷贝,大大减少了内存消耗。两者都支持随机访问(下标访问),尾部插入/删除,中间插入/删除。
主要函数:插入:insert(position,value) 删除:erase(position)
QVector独有函数:remove(i,count = 1) i:索引i处的元素 从i元素开始删除count个元素
二、栈(QStack和std::stack)
QStack与std::stack由于其底层依赖不同,导致功能接口存在较大差异。QStack继承自QVector,所以可以额外使用QVector所有方法(支持insert erase 同时在标准栈操作基础上扩展了push_front、push_back、pop_front、pop_back)由于双端都支持操作,在一定程度上违背了栈的原则(单端进出),在使用push/pop_front/back时需要特别注意元素存储顺序。而stack基于std::deque(双端队列)实现,可指定 vector或list作为底层容器,虽然基于双端队列实现,但基于栈的特性,会把栈封装在一端,所以仅提供标准栈操作(push/pop/top等不能进行中间或尾部插值与删除)
标准栈操作函数:
栈顶入栈: push() 栈顶出栈:pop() 返回栈顶应用:top()
判断栈是否为空:empty() 返回栈中元素数量:size()
三、队列(QQueue与std::queue)
与栈类似,QQueue继承自QList,直接使用链表式数组实现,std::queue基于std::deque实现,可指定list作为底层容器。std::queue同样只提供标准队列操作
标准队列操作函数:
队尾入队:push() 队顶出队:pop() 队列元素个数:size()
判断栈是否为空:empty() 返回队首元素:front() 返回队尾元素:back()
QQueue特有的函数:
入队:enqueue() = push_back() 添加到队尾 push_front ()添加到队首(违背先进先出原则)
出队:dequeue() pop_front() 移除队首元素 pop_back() 移除队尾元素
dequeue()都会返回相应的元素值 而pop仅仅执行删除操作
获取队列头元素: head() 获取队列尾元素:last() 清空队列:clear()
四、列表
列表这块涉及到内存池的使用,导致两者底层实现不一致,目前还不是很了解原理,不再深究。之后遇到有空再补充列表以及后面几个数据结构。
这里展示一个使用Qt模板类开发的小例子
#include <random>
#include <QCoreApplication>
#include <QDebug>
#include <QQueue>
#include <QStack>
#include <QVector>
//人造松枝
/*需求:将各种尺寸的塑料松针插到松枝上
* 工人有一个小盒子 盒子从上到下能放置N个松针 工人紧靠传送带 传送带上有M个松针
* 有充足的松枝干,工人在插完松枝干第一个松针后 下一个松针必须不大于上面的松针
* 工人每次优先从小盒子取松针 若小盒子为空或不符合要求则从传送带取松针
* 当传送带取到的松针也不符合要求时,便放入小盒子 寻找下一根松针
* 当发生下列三种情况会结束手中的松枝制作
* 1.小盒子满了 但推送器上的松针仍无法满足要求
* 2.小盒子最上面松针不满足要求,但传送带上已经没有松针了
* 3.手中的松枝插满了松针
*
* 现给定传送带M根松针大小 以及小盒子和松枝容量 球每根成品松枝的信息
*/
void tryQSTL(){
QQueue<int> conveyor; //传送带队列先进先出
QStack<int> box; //盒子栈先进后出
QVector<int> current_branch; //当前松枝的松枝序列
const int boxmaxsize = 5; //栈的最大深度 盒子的最大容量
const int K = 10; //松枝的最大容量
int count = 30; //传送带松针数量
int last_pine_needle = 21 ; //当前松针大小
int number = 0; //当前松枝序号
//使用随机值模拟传送带上松针大小
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<>randsize(5,20);
for(int i = 0;i<count;i++){
int needle;
needle = randsize(gen);
conveyor.push_back(needle); //入队
}
while(count >= 0){
if(current_branch.size()==K){ //首先判断松枝干是否已经插满松针
number++;
qDebug()<<"当前松枝的序号:"<<number;
for(int i :current_branch){
qDebug().nospace().noquote()<< i ; //禁用换行符输出
}
qDebug() <<"over";
current_branch.clear();
last_pine_needle = 21;
continue;
}
//判断传送带是否还有松针如果没有松针便不能执行从传送带取松针操作
if(count == 0&&box.empty()){
qDebug() << "任务完成";
break;
}else if(count == 0&&(!box.empty())){
if(box.top() > last_pine_needle){
number++;
qDebug() <<"当前松枝的序号:" <<number;
for(int i:current_branch){
qDebug().nospace().noquote() << i;
}
qDebug() << "over";
current_branch.clear();
last_pine_needle = 21;
continue;
}else{
last_pine_needle = box.pop();
current_branch.append(last_pine_needle);
continue;
}
}
//根据盒子情况进行不同的操作
if(box.size() == boxmaxsize){
if(box.top()>last_pine_needle){
if(conveyor.front()>last_pine_needle){
number++;
qDebug()<<"当前松枝的序号:"<<number;
for(int i :current_branch){
qDebug().nospace().noquote()<< i ;
}
qDebug() <<"over";
current_branch.clear();
last_pine_needle = 21;
continue;
}else{
last_pine_needle = conveyor.front();
conveyor.pop_front();
current_branch.append(last_pine_needle);
count--;
continue;
}
}else{
last_pine_needle = box.pop();
current_branch.append(last_pine_needle);
continue;
}
}
if(box.size()<boxmaxsize){
if(box.empty()||box.top()>last_pine_needle){
if(conveyor.front() > last_pine_needle){
box.push(conveyor.front());
conveyor.pop_front();
count--;
continue;
}else {
last_pine_needle = conveyor.front();
current_branch.append(last_pine_needle);
conveyor.pop_front();
count--;
continue;
}
}else{
last_pine_needle = box.pop();
current_branch.append(last_pine_needle);
continue;
}
}
}
}
int main(int argc, char *argv[])
{
tryQSTL();
return 0;
}

被折叠的 条评论
为什么被折叠?



