3-2 队列
时间:2022-06-24
本文章向大家介绍3-2 队列,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
1、基本概念
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行删除操作的端称为队头 ,进行插入操作的端称为队尾。
FIFO (First In First Out) 先进先出
队列的基本操作:
①init() 置空,将队列Q初始化为空;
②empty() 判队列空,
③size() 返回队列中元素的个数
④front() 取队头元素,若队列未空,则函数返回队头 数据元素。
⑤rear() 取尾头元素,若队列未空,则函数返回队尾 数据元素。
⑥push(x) 入队列,若队列未满,在原队尾后加入数据元素x,使x成为新的队尾元素;
⑦pop() 出队列,若队列未空,则将队列的队头元素删除。
队列存储结构的实现有以下两种方式:顺序队列 、 链式队列
2、顺序队列
在顺序表的基础上实现的队列结构;
一般情况下,rear等于max时,说明队尾元素应占据了顺序表的最后一个存储位置,即无法再从队尾插入新元素,
这个时候判定为“队满”,但是如果说队首元素前面还有空的位置,那么说明我们这个顺序表还是有空间可以存放元素的,
所以rear == max 称为 “假溢出”,那么只要改动一下判别“队满”的条件,就可以把顺序队列 当作 循环队列 来使用了:
①头文件:
#ifndef SQ_QUEUE_H_
#define SQ_QUEUE_H_
#define MAX 10
struct sq_queue {
int data[MAX];
int front;//队首标记
int rear;//队尾标记
};
void Init(sq_queue *q);
bool Empty(sq_queue *q);
int Len(sq_queue *q);
bool Full_SQ(sq_queue *q);
bool Full_Circle(sq_queue *q);
int Front(sq_queue *q);
int Rear(sq_queue *q);
int Pop(sq_queue *q);
void Push_sq(sq_queue *q, int x);
void Push_circle(sq_queue *q, int x);
void Show(sq_queue *q);
#endif // !SQ_QUEUE_H_
②函数定义文件:
#include<iostream>
#include"sq_queue.h"
using std::cin;
using std::cout;
using std::endl;
/*初始化*/
void Init(sq_queue *q) {
q->front = q->rear = 0;
}
/*判空*/
bool Empty(sq_queue *q) {
if (q->front == q->rear)
return true;
else
return false;
}
/*返回长度*/
int Len(sq_queue *q) {
//这个公式对于循环队列 和 非循环普通队列都适用
return (q->rear - q->front + MAX) % MAX;
}
/*普通顺序队列的 判满条件, 会有假溢出现象*/
bool Full_SQ(sq_queue *q) {
if (q->rear == MAX)
return true;
else
return false;
}
/*循环顺序队列的 判满条件, 能利用front前面的空间存储元素*/
bool Full_Circle(sq_queue *q) {
if ((q->rear + 1) % MAX == q->front)
return true;
else
return false;
}
int Front(sq_queue *q) {
if (Empty(q))
return NAN;
else
return q->data[q->front];
}
int Rear(sq_queue *q) {
if (Empty(q))
return NAN;
else
return q->data[q->rear-1];//由于rear指向队尾元素的下一个位置,所以这里要 -1
}
int Pop(sq_queue *q) {
if (Empty(q))
return NAN;
else
return q->data[q->front++];
}
void Push_sq(sq_queue *q, int x) {
/*普通顺序队列的情况*/
if (Full_SQ(q))
return;
else
q->data[q->rear++]=x;
}
void Push_circle(sq_queue *q, int x){
/*循环队列的情况*/
if (Full_Circle(q))
return;
else {
q->rear = q->rear % MAX;
q->data[q->rear] = x;
q->rear++;
}
}
void Show(sq_queue *q) {
if (Empty(q))
return;
else {
for (int i = q->front; i < MAX; i++)
cout << q->data[i] << " ";
if (q->rear < q->front)
for (int j = 0; j < q->rear; j++)
cout << q->data[j] << " ";
}
cout << endl;
}
③主函数文件:
#include<iostream>
#include"sq_queue.h"
using std::cin;
using std::cout;
using std::endl;
int main() {
sq_queue q1;
Init(&q1);
cout << "nthe queue is empty: " << Empty(&q1) << " and its length is: " << Len(&q1) << endl;
int i = 0;
cout << "n先将所有位置都填上元素:n";
//先用顺序队列的判满条件
while (!Full_SQ(&q1)) {
Push_sq(&q1, i);
i++;
//cout << q1.front <<" "<<q1.rear<< endl;
//getchar();
}
Show(&q1);
cout << "n然后将队首的3个元素依次出队列:n";
Pop(&q1); Show(&q1);
Pop(&q1); Show(&q1);
Pop(&q1); Show(&q1);
cout << "n根据普通顺序队列的判满条件,它是一个满队列:Full_SQ =" << Full_SQ(&q1) << endl;
cout << "n根据循环队列的判满条件,它不是一个满队列:Full_Circle = " << Full_Circle(&q1) << endl;
cout << "n所以如果使用循环队列的判满条件,我们可以继续入队列,添加元素:n";
//再用循环队列的判满条件
while (!Full_Circle(&q1)) {
Push_circle(&q1, i);
i++;
}
Show(&q1);
cout << "n但是能存储的元素的数目要比普通顺序队列少一个n";
cin.get();
return 0;
}
3、链式队列
采用链表来实现队列,我还是选用带头结点的单链表来实现,因为其在第一个位置删除时,不用改变头指针;
我们在插入的时候,选择在链表尾部使用尾插法插入,所以链表尾部视为队尾rear;
在删除时,删除头结点后的首结点,为了方便起见,我们可以把头结点认为是front,这样front就一直不会变化,比较方便
如图所示:
①头文件
#ifndef LINK_QUEUE_H_
#define LINK_QUEUE_H_
/**/
/**/
/*结点的定义*/
typedef struct Link_list_node {
int data;
struct Link_list_node *next;
}node;
/*链式队列结构定义*/
typedef struct link_queue {
node * front;
node * rear;
}lq;
void Init(lq * q);
bool Empty(lq * q);
void Destroy(lq *q);
int Size(lq *q);
int Front(lq *q);
int Rear(lq *q);
int Pop(lq *q);
void Push(lq *q, int x);
void Show(lq *q);
#endif // !LINK_QUEUE_H_
②函数定义文件
#include<iostream>
#include"link_queue.h"
using std::cin;
using std::cout;
using std::endl;
void Init(lq * q) {
/**/
q->front = new node;
q->front->next = nullptr;
q->rear = q->front;
}
bool Empty(lq * q) {
if (q->front == q->rear)
return true;
else
return false;
}
void Destroy(lq *q) {
node *p;
while (q->front != nullptr) {
p = q->front->next;
delete q->front;
q->front = p;
}
q->rear = nullptr;
}
int Size(lq *q) {
node *p = q->front;
int j = 0;
while (p->next != nullptr) {
p = p->next;
j++;
}
return j;
}
int Front(lq *q) {
if (Empty(q))
return NAN;
else
return q->front->next->data;
}
int Rear(lq *q) {
if (Empty(q))
return NAN;
else {
node *p = q->front;
while (p->next != nullptr)
p = p->next;
return p->data;
}
}
int Pop(lq *q) {
if (Empty(q))
return NAN;
else {
//创建一个结点指向队首元素
node *p = q->front->next;
//将队首元素从链表中断开
q->front->next = p->next;
//存储此队首元素的值
int x = p->data;
//如果删除的这第一个元素恰好是rear,就需要更新rear的值为front,即空队列的情况
if(p==q->rear)
q->rear = q->front;
delete p;
return x;
}
}
void Push(lq *q, int x) {
//创建一个结点接受新的值
node *s = new node;
s->data = x;
s->next = nullptr;
//将其插入链表的最后1个位置,即采用尾插法
/*传统思路是通过遍历的方式找到最后一个结点*/
/*
node *p = q->front;
while (p->next != nullptr) {
p = p->next;
}
p->next = s;
*/
/*但是我们这里已经有最后一个结点的地址了,那就是rear!*/
q->rear->next = s;;
q->rear = s;
}
void Show(lq *q) {
node*p = q->front;
while (p->next != nullptr) {
p = p->next;
cout << p->data << " ";
}
cout << endl;
}
③主函数文件
#include<iostream>
#include"link_queue.h"
using std::cin;
using std::cout;
using std::endl;
int main() {
lq q1;
Init(&q1);
cout << "nthe queue is empty: " << Empty(&q1) << " and its length is: " << Size(&q1) << endl;
int x = 0;
cout << "n在队尾插入元素,按 q 表示结束:n";
while (cin>>x) {
Push(&q1, x);
cout << "the queue is: ";
Show(&q1);
}
cin.clear();
while (cin.get() != 'n')
continue;
cout << "n在队头弹出元素n";
while (!Empty(&q1)) {
cout<<"ndelete: "<<Pop(&q1);
cout << "nthe queue is: ";
Show(&q1);
}
Destroy(&q1);
cin.get();
return 0;
}
如有错误,请不吝指出,谢谢
- Elasticsearch聚合初探——metric篇
- AngularJS API之$injector ---- 依赖注入
- AngularJS API之extend扩展对象
- AngularJS API之equal比较对象
- Elasticsearch之_default_—— 为索引添加默认映射
- Elasticsearch 动态映射——自动检测
- Elaticsearch REST API常用技巧
- C++拷贝构造函数
- 记录安装oracle的那些事(一)之oracle我很大
- Elasticsearch 连接查询
- 小程序加戏成功!变身游戏成新版微信最大主角,用户玩得不亦乐乎
- 堆实例
- 大数加法
- Express开发实例(2) —— Jade模板引擎
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法