队列

1.定义

只能在表的一端进行插入运算 在表的另一端进行删除运算的线性表(头插尾删)

  • 逻辑结构:与线性表相同
  • 存储结构:顺序表或者链表 以循环顺序队列常见
  • 运算规则:只能在队首和队尾运算,先进先出
  • 实现方式:掌握入队和出队的操作

注:采用顺序存储的队列一般常用循环队列

所以说队列是一种先进先出的线性表,相应的也有顺序存储和链式存储两种方式

1.顺序存储就是用数组实现,比如有一个n个元素的队列,数组下标0的一端是队头,入队操作就是通过数组下标一个个顺序追加,不需要移动元素,但是如果删除队头元素,后面的元素就要往前移动,对应的时间复杂度就是O(n),性能自然不高。

为了提高出队的性能,就有了循环队列,什么是循环队列呢?

就是有两个指针,front指向队头rear指向对尾元素的下一个位置,元素出队时front往后移动,如果到了对尾则转到头部,同理入队时rear后移,如果到了对尾则转到头部,这样通过下标front出队时,就不需要移动元素了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kbYMlus0-1664849178379)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220930164447821.png)]

同时规定,当队列为空时,front和rear相等,那么队列什么时候判断为满呢?

按照循环操作rear依次后移,然后再从头开始,也是出现rear和front相等时,队列满。这样跟队列空的情况就相同了,为了区分这种情况,规定数组还有一个空闲单元时,就表示队列已满,因为rear 可能在front后面,也可能循环到front前面,所以队列满的条件就变(rear+1)%maxsize = front ,同时队列元素个数的计算就是(rear -front+maxsize)%maxsize。

2.基本操作

  • 1.init 初始化

2.destroy 销毁队列
3.clear 清空队列
4.queue 返回队长
5.gethead 返回队头元素
6.enqueue 插入元素
7.dequeue 删除队头
8.队列置空
9.遍历

3.队列重要操作

入队和出队

  • 初始化 队空 front == rear = 0
  • 入队:base[rear] = x; 队尾进行入队
  • rear++;
  • 出队:x = base[front]; 队头开始
  • front++;
  • 空队标志:front == rear

溢出问题

  • rear == maxsize 溢出
  • 若front = 0
  • rear=maxsize 真溢出
  • 若front !=0
  • rear=maxsize 假溢出

解决上溢的方法:

  • 采用循环队列
  • 取模方法 模运算
  • 插入:q->base[q->rear] = x;
  • rear = (rear + 1)% maxsize;回到0
  • 删除:front = (front+1)%maxsize

判断队空和队满:

  • 1.设置一个标志 区别队空 堆满
  • 2.另外设置一个变量,记录元素个数
  • 3.->少用一个元素空间
  • 队空:rear == front
  • 队满:(rear+1)%maxsize = front

注:采用模运算的主要原因是:

1.控制在可控的范围之内,防止溢出

2.限定范围

4.代码实现

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef int qelemtype;
#define maxsize 9 //最大队列长度
 
//顺序的 循环队列
typedef struct
{
	qelemtype* base;//初始化的动态分配存储空间 存储队列的元素
	// 队头 队尾
	int front;//头指针 若队列不空 指向队列头元素
	int rear;//尾指针 若队列不空 指向队尾元素的下一个位置
}Queue;

//初始化
void initqueue(Queue *q)
{
	q->base = (qelemtype*)malloc(sizeof(qelemtype) * maxsize);//数组存储 首元素的地址就是一个指针
	if (!q->base)
	{
		printf("队列开辟失败!");
		exit(-1);
	}
	q->front = 0;
	q->rear = 0;
}
//求队长
int QueueLen(Queue *q)
{
	int len = (q->rear - q->front + maxsize) % maxsize;
	//printf("%d", len);
	return len;
	//循环队列(q->rear - q->front + maxsize)%maxsize
}

//入队
int pushq(Queue *q,qelemtype x)
{
	
	if ((q->rear+1)%maxsize == q->front)
	{
		printf("队满!");
	}
	q->base[q->rear] = x;
	q->rear =( q->rear + 1) % maxsize;
	return 1;
}
//出队
int popq(Queue *q)
{
	int x;
	if (q->rear == q->front)
	{
		printf("队空!");
	}
	x = q->base[q->front];
	q->front= (q->front + 1) % maxsize;
	return x;
}
//去队头元素
int gettop(Queue *q)
{
	if (q->rear == q->front)
	{
		printf("队空!");
	}
	return  q->base[q->front];
}

int main()
{
	Queue q;
	//int n;
	printf("队列初始化!\n");
	initqueue(&q);
	printf("队列初始化成功!\n");
	printf("请求入队:\n");
	/*printf("输入入队个数:\n");
	scanf("%d", &n);
	printf("输入入队元素:\n");*/
	pushq(&q, 1);
	pushq(&q, 31);
	pushq(&q, 41);
	pushq(&q, 51);
	pushq(&q, 1);
	pushq(&q, 31);
	pushq(&q, 41);
	pushq(&q, 41);
	printf("入队成功:\n");
	printf("请求出队:\n");
	printf("%d ", popq(&q));
	printf("%d ", popq(&q));
	printf("%d ", popq(&q));
	

	int len = QueueLen(&q);
	printf("队长为:%d\n", len);
	return 0;

}