一文讲清 c++ 之队列

2023-10-30

队列也是一种特殊的 “表”,使用队列时插入是在一端操作,而删除则是在另外一端

1.队列模型

队列的基本操作是enqueue(入队),它是在表的末端(称为队尾)插入--个元素;dequeue(出队),它是删除(并返回)表的开头(叫作队头)的元素。下图显示了一个队列的抽象模型。

 2.链表实现队列

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

struct Node{
	int val;
	Node* next;
	Node(int v){
		val = v;
		next = NULL;
	}
};
class Queue{
	int size;
	Node* head; //pointer to the font node
	Node* back;	//pointer to the least node
public:
	Queue(){
		size = 0;
		head = back = NULL;
	}
	bool empty(){
		return size == 0;
	}
	Node* front(){
		return head;
	}
	Node* push_back(int v){
		if (size == 0){
			//note that head-next should give valuation after head
			head->next = head = back = new Node(v);
		}
		else if (size == 1){
			head->next = back = new Node(v);
		}
		else {
			back->next = new Node(v);
			back = back->next;
		}
		size++;
		return back;
	}
	//delete the font node
	void pop(){
		if (empty()) return;
		Node* temp = head;
		head = head->next ;
		delete temp;
		size--;
	}
};

void test_queue(){
	Queue queue;
	int n;
	cin >> n;
	for (int i = 0; i < n; i++){
		int temp;
		cin >> temp;
		queue.push_back(temp);
	}
	//you have to judge if queue is empty before using this font node
	while (queue.empty() == false){
		cout << queue.front()->val << endl;
		queue.pop();
	}
	return;
}

int main(){
	test_queue();
	return 0;
}

2.用数组实现

对于每一个队列数据结构,我们保留一个数组theArray以及位置front和back,它们代表队列的两端。我们还要记录实际存在于队列中的元素的个数currentsize。下图表示处于某个中间状态的一个队列。

 操作应该是清楚的。要enqueue元素x,可将currentsize和 back增1,然后置theArray[back]=x。要dequeue一个元素,可以置返回值为theArray[front],将currentsize减1,再将front增1。其他的方法也可以使用(将在后面讨论)。现在论述错误的检测。

这种实现存在一个潜在的问题。经过10次enqueue后,队列似乎是满了,因为back现在是数组的最后一个下标,而下一次执行enqueue就会是一个不存在的位置。然而,队列中也许只存在几个元素,因为若干元素可能已经出队了。像栈一样,即使在有许多操作的情况下队列也常常不是很大。

简单的解决方法是,只要front或back到达数组的尾端,就绕回到开头。下列图显示了在某些操作期间的队列情况。这称为循环数组(circular array)实现可以看成换环队列。

 环形队列与普通队列的区别:

1.front头部指针

一般队列:front头部指针初始值为-1,从队列取数据时,该值依次递增,指向的元素即待取出的数据,而队列的头部数据所在的指针位置为front+1。当front=maxSize-1时,队列最后一个数据取出,此时队列为空。

环形队列:front头部指针初始值为0,指向的元素既是队列的头部数据也是待取出的数据。从队列取数据时,因逻辑上的闭环,指针可能再次回到前面的位置,不能单一递增处理,需通过取模来重新计算指针的值。

2.rear尾部指针

一般队列:rear尾部指针初始值为-1,队列添加数据时,该值依次递增,当rear=maxSize-1时,队列满,无法再添加数据。

环形队列:rear尾部指针初始值为0,指向待添加数据的位置,队列添加数据时,因逻辑上的闭环,指针可能再次回到前面的位置,不能单一递增处理,会出现角标越界异常,需通过取模来重新计算指针的值。

3.队列空的判断逻辑

一般队列:rear == front时,队列空。

环形队列:rear == front时,队列空。

4.队列满的判断逻辑

一般队列:rear = maxSize - 1时,队列满。

环形队列:(rear + 1) % maxSize == front时,队列满。

代码实现:

#include <iostream>
#include <cstdlib>
#include <memory.h>
 
class Ciclequeue
{
    public:
        //队列最大容量
	int m_maxSize;
	//队列头指针
	int m_frontIdx;
	//队列尾指针
	int m_rearIdx;
	//队列数组
	int *m_queueArr;
    public:
	//构造函数
    	Ciclequeue(int tmpSize)
	{
	    m_maxSize = tmpSize;
	    m_frontIdx = 0;
	    m_rearIdx = 0;
            m_queueArr = new int[m_maxSize];
	    memset(m_queueArr, 0 , sizeof(int)*m_maxSize);
	}
		
	//析构函数
	~Ciclequeue()
	{
	    delete m_queueArr;
	    m_queueArr = NULL;
	}
 
	//入队
	void enqueue(int datavalue)
	{
	    if(isfull())
	    {
		std::cout<<"Queue is full!"<<std::endl;
		return;
	    }
 
	    m_queueArr[m_rearIdx] = datavalue;
	    m_rearIdx = (m_rearIdx + 1)%m_maxSize;
	}
 
	//出队
	void dequeue()
	{
	    if(isempty())
	    {
		std::cout<<"Queue is empty!"<<std::endl;
		return;
	    }
			
    	    m_queueArr[m_frontIdx] = -1; //模拟出队列动作
	    m_frontIdx = (m_frontIdx + 1)%m_maxSize;
	}
 
	//检查队列是否已满
	bool isfull()
	{
	    if(m_maxSize == -1)
	    {
		std::cout<<"Create queue error!"<<std::endl;
		return false;
	    }
	    return (m_rearIdx + 1)%m_maxSize == m_frontIdx;
	}
 
	//检查队列是否为空
	bool isempty()
	{
	    if(m_maxSize == -1)
	    {
		std::cout<<"Create queue error!"<<std::endl;
		return false;
	    }
	    return m_rearIdx == m_frontIdx;
	}
 
	//当前队列元素各个数
	int size()
	{
	    return (m_rearIdx - m_frontIdx + m_maxSize) % m_maxSize;
	}
 
	//显示队列
	void showqueue()
	{
	    if(isempty())
	    {
		return;
	    }
 
	    for(int i = m_frontIdx; i < m_frontIdx + size(); i++ )
	    {
		std::cout<<m_queueArr[i]<<" "<<std::endl;
	    }
	}
 
	//显示队列头
	void showqueuefront()
	{
	    std::cout<<m_queueArr[m_frontIdx]<<std::endl;
	}
};
 
int main(int argc, char **argv) 
{
	int tmpSize = std::atoi(argv[1]);
	if(tmpSize <= 0)
	{
		std::cout<<"Set MaxSize Error!"<<std::endl;
		return 0;
	}
 
	Ciclequeue *testqueue = new Ciclequeue(tmpSize);
	testqueue->enqueue(3);
	testqueue->enqueue(2);
	testqueue->dequeue();
	testqueue->enqueue(4);
	testqueue->dequeue();
	testqueue->enqueue(5);
	testqueue->enqueue(66);
	testqueue->enqueue(88);
	testqueue->enqueue(1204);
 
	testqueue->showqueue();
 
	delete testqueue;
	testqueue = NULL;
 
    return 0;
}
 

3.队列的应用

关于计算机网络的。有许多种PC机的网络设置,其中磁盘是放一台叫作文件服务器(file server)的机器上的。使用其他计算机的用户是按照先到先使用的原则访问文件的,

因此其数据结构是一个队列

升级:

一个称为排队论(queuing theory)的数学分支用概率的方法处理--些诸如计算用户预计要排队等待的时间、等待的队伍能够排多长等类问题。问题的答案依赖于用户加入队列的频率以及-一旦用户得到服务时处理服务花费的时间。这两个参数作为概率分布函数给出。在一些简单的情况下,答案可以解析地算出。一种简单的例子是条电话线有一个接线员。如果接线员忙,打来的电话就被放到个等待队列中(这还与某个容许的最大限度有关)。这个问题在商业上很重要,因为研究表明,人们会很快挂上电话。如果有k个接线员,那么这个问题解决起来要困难得多。解析求解困难的问题往往使用模拟的方法求解。此时,需要使用一个队列来进行模拟。如果k很大,那么还需要其他一些数据结构来使得模拟更有效地进行。

关注我一起学!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一文讲清 c++ 之队列 的相关文章

随机推荐

  • 记Tomcat删除war包问题

    由于不清楚tomcat部署原理 误认为tomcat部署完成之后 可以把war删除 然后以后每次部署 只需要增量部署就行了 然后还怕由于war包的存在 增量部署的内容会被覆盖掉 不清楚war包什么时候会自动重新部署 于是 rm rf mm w
  • Python将.py文件打包成.exe可执行文件

    1 安装Pyinstaller库 pip install pyinstaller 2 在 py文件的所在文件夹Shift 右键 打开后输入pyinstaller F 要打包的文件名称 例如Mqtt py F参数表示覆盖打包 如果有旧的会覆盖
  • [电路设计]按键方案

    电路设计 按键方案 本文记录和介绍几种按键解决方案 包括普通按键 按键编码电路 ADC按键的工作原理 1 普通按键 一般使用的按键原理图如下图所示 由按键 上拉电阻和消抖滤波电容组成 按键断开时 K e y I i n
  • 级数求和公式

    级数求和公式是用于求解有限的或无限的等差 等比数列的总和 它的一般形式为 Sn a1 a2 a3 an 其中 a1 为该级数的首项 an 为该级数的末项 Sn 表示该级数的和 1 如果是有限等差数列 其求和公式为 Sn n a1 an 2
  • Spring Cloud Eureka注册中心组件搭建

    第一步 Idea 新建spring boot项目 选中Cloud 中 Eureka Server 第二部 配置文件 将application application 后缀改为application yml 也可以不修改 我是用的yml 粘贴
  • 计算机指令格式

    计算机的指令格式与机器的字长 存储器的容量及指令的功能都有很大的关系 从便于程序设计 增加基本操作并行性 提高指令功能的角度来看 指令中应包含多种信息 但在有些指令中 由于部分信息可能无用 这将浪费指令所占的存储空间 并增加了访存次数 也许
  • idea中处理依赖注入爆红问题

    1 这是idea里的编译异常 这里会出现依赖注入爆红的情况 有以下两种方式 1 1 方式一 在进行注入的时候 并没有UserMapper这个接口 所以爆异常 解决方式 需要创建一个UserMapper接口并交给Spring容器管理 1 2
  • 【转】伺服电机三环控制的原理(位置环,运动环,电流环)

    运动伺服一般都是三环控制系统 从内到外依次是电流环速度环位置环 1 首先电流环 电流环的输入是速度环PID调节后的那个输出 我们称为 电流环给定 吧 然后呢就是电流环的这个给定和 电流环的反馈 值进行比较后的差值在电流环内做PID调节输出给
  • 剑指offer(C++版本)

    剑指offer c 版本 二维数组查找 替换空格 从尾到头打印链表 重建二叉树 用两个栈实现队列 旋转数组的最小数字 斐波那契数列 跳台阶 矩阵覆盖 二进制1的个数 数值的整数次方 调整数组顺序使奇数位于偶数前面 链表中倒数第k个结点 反转
  • 【ANN预测】基于遗传算法优化 ANN附matlab代码

    作者简介 热爱科研的Matlab仿真开发者 修心和技术同步精进 matlab项目合作可私信 个人主页 Matlab科研工作室 个人信条 格物致知 更多Matlab仿真内容点击 智能优化算法 神经网络预测 雷达通信 无线传感器 电力系统 信号
  • qt在windows下交叉编译arm架构程序

    1
  • 《Kubernetes部署篇:Ubuntu20.04基于二进制安装安装kubeadm、kubelet和kubectl》

    一 背景 由于客户网络处于专网环境下 使用kubeadm工具安装K8S集群 由于无法连通互联网 所有无法使用apt工具安装kubeadm kubelet kubectl 当然你也可以使用apt get工具在一台能够连通互联网环境的服务器上下
  • 单淘汰赛制两队相遇算法

    对于这种单循环赛制acm也是常遇到这样的题那么 对于这样的比赛我们要怎么模拟所有的可能是一个问题 我们如何判断两个队在某一轮是否会遇到呢 我们其实可以利用二进制的性质 设某一轮比赛为i 求j和k两只队伍是否能比赛 下面我们用二进制来表示队伍
  • vp8-vp9-ivf文件格式

    经常遇到ivf格式 下面看看它的头 typedef struct ivf header 0 3 固定的 DKIF 字符串 4 5 version 应该为0 6 7 header的字节长度 8 11 编码器的FourCC e g VP80 1
  • 在内嵌窗口中调用父窗口的javascript代码

    noname1 html noname2 html
  • 【原创】【硬件电路】AltiumDesigner18规则检查含义

    文章首发于同名微信公众号 DigCore 欢迎关注同名微信公众号 DigCore 及时获取最新技术博文 Layout时最常用的错误检查 这需要在布局布线前做好规则设置 所谓磨刀不误砍柴工 尤其是在Layout时 如果违反规则 就会亮起绿色
  • vue.config.js配置详解

    1 vue inspect rule 命令获取vue config js中的chainWebpack配置项 2 vue inspect rule svg 筛选配置项 const path require path function reso
  • Rattle :基于R的数据挖掘工具(3):载入数据

    数据 数据是进行数据挖掘工作的基础 要是没有数据 那也就没什么可挖的了 当今时代 数据的丰富超乎想象 它可以是数字 也可以是文本 图像 声音 视频等各种形式的存在 但是要把数据变成知识和信息 并不是一件简单的事 关于数据的一般术语 一个数据
  • C语言有参函数调用时参数间数据传递问题

    C语言有参函数调用时参数间数据传递问题 C语言中在发生有参函数调用时 实参变量与形参变量之间的数据都是单向的 值传递 方式 包括指针变量和数组名作参数的情况 C语言要求函数的实参要有确定的值 在函数调用时给形参分配相应的内存单元 同时将实参
  • 一文讲清 c++ 之队列

    队列也是一种特殊的 表 使用队列时插入是在一端操作 而删除则是在另外一端 1 队列模型 队列的基本操作是enqueue 入队 它是在表的末端 称为队尾 插入 个元素 dequeue 出队 它是删除 并返回 表的开头 叫作队头 的元素 下图显