队列
队列是运算受限的线性表,和线性表一样也是线性结构,只不过插入只能在队尾插入称为入队,删除只能在队头删除称为出队,和日常生活中的排队顺序一样,是先进先出(FIFO)的线性表。队列存储结构分为顺序存储和链式存储,本文主要介绍最常用的 循环顺序存储队列.
溢出现象
当队空的时候出队 就会产生下溢;
上溢分为真上溢和假上溢,真上溢:当队满的时候入队会产生真上溢。
假上溢主要发生在当入队和出队操作,头指针指增加不减少,致使被删除元素的空间永远无法被利用,当队列中实际元素个数远远小于向量空间的规模时,也有可能超越向量空间的上界而不能做入队操作,那么这种现象就称之为“假上溢”现象.
为了解决假上溢现象,引入循环队列(放弃一个结点空间,当rear+1达到 MAXSIZE时,将rear重新指向 “队头” 已出队那一端)
优点:
节省存储空间:循环顺序存储结构可以利用数组来存储队列元素,不需要额外的指针空间,节省了存储空间。
操作简单高效:循环顺序存储结构可以通过数组的下标来直接访问队列元素,操作简单高效,插入和删除操作的时间复杂度为O(1)。
缺点:
需要预先确定队列的最大长度:循环顺序存储结构需要预先确定队列的最大长度,如果队列长度超出预设长度,需要进行扩容操作,可能会导致元素搬移,影响性能。
需要处理循环队列的溢出问题:循环顺序存储结构需要处理循环队列的溢出问题,即队列头尾指针相遇时的处理,可能会增加代码的复杂度。
代码实现(C语言)
定义
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int DataType;
typedef struct{
DataType *data;
int front; //队头
int rear; //队尾
}SeqQueue;
初始化
Status InitQueue(SeqQueue *Q)
{
Q->data = (DataType *)malloc(sizeof(DataType) * MAXSIZE);//申请内存结点
if(!Q->data) //如果申请失败
exit(OVERFLOW);
Q->front = Q->rear = 0;
return OK;
}
判队空
Status IsEmpty(SeqQueue *Q)
{
return Q->front == Q->rear; //头指针和尾指针相等时 队空
}
判队满
Status IsFull(SeqQueue *Q)
{
return (Q->rear+1) % MAXSIZE == Q-> front; //队满条件 (有一个结点空间没有使用,另外一种方法是设置一个计数器,入队计数器+1,判队满就是看计数器和MAXSIZE相不相等)
}
求队列长度
int GetLength(SeqQueue *Q)
{
return (Q->rear - Q->front + MAXSIZE) % MAXSIZE;
}
入队
时间复杂度O(1)
Status EnQueue(SeqQueue *Q,DataType x)
{
if(IsFull(Q)) //队满返回 TRUE 1
{
printf("队满,不能入队!")
return ERROR;
}
Q->data[Q->rear] = x; //入队元素赋值
Q->rear = (Q->rear +1) % MAXSIZE; //队尾指针 + 1
return OK;
}
出队
时间复杂度O(1)
Status DeQueue(SeqQueue *Q, DataType *x)
{
if(IsEmpty(Q))
{
printf("队空不能出队!");
return ERROR;
}
*x = Q->data[Q->front]; //队头指针的元素值取出来
Q->front = (Q->front +1) % MAXSIZE;
return OK;
}
取队头元素
DataType GetHead(SeqQueue *Q)
{
if(IsEmpty(Q))
{
printf("队空不能取队头!");
return ERROR;
}
return Q->data[Q->front];
}
显示队中所有元素
void ShowQueue(SeqQueue *Q)
{
int p =Q->front;
if(p == Q->rear)
printf("队空,无元素!");
else
{
printf("从队头起,队列中各元素为:");
while(p != Q->rear)
{
printf("%5d",Q->data[p]);
p++;
}
}
}
完整示例(C语言实现)
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int DataType;
typedef struct{
DataType *data;
int front; //队头
int rear; //队尾
}SeqQueue;
//初始化队列
Status InitQueue(SeqQueue *Q)
{
Q->data = (DataType *)malloc(sizeof(DataType) * MAXSIZE);
if(!Q->data)
exit(OVERFLOW);
Q->front = Q->rear =0;
return OK;
}
//判队空
Status IsEmpty(SeqQueue *Q)
{
return Q->front == Q->rear;
}
//判队满
Status IsFull(SeqQueue *Q)
{
return (Q->rear + 1) % MAXSIZE == Q->front;
}
//求队列长度
int GetLength(SeqQueue *Q)
{
return (Q->rear - Q->front + MAXSIZE) % MAXSIZE;
}
//入队
Status EnQueue(SeqQueue *Q, DataType x)
{
if(IsFull(Q))
{
printf("队满,不能入队元素!");
return ERROR;
}
Q->data[Q->rear] = x;
Q->rear = (Q->rear + 1) % MAXSIZE;
return OK;
}
//出队
Status DeQueue(SeqQueue *Q, DataType *x)
{
if(IsEmpty(Q))
{
printf("队空,不能出队元素!");
return ERROR;
}
*x = Q->data[Q->front];
Q->front = (Q->front+ 1) %MAXSIZE;
return OK;
}
//取队头元素
DataType GetHead(SeqQueue *Q)
{
if(IsEmpty(Q))
{
printf("队空,不能取队头元素!");
return ERROR;
}
return Q->data[Q->front];
}
//显示队中所有元素
void ShowQueue(SeqQueue *Q)
{
int p =Q->front;
if(p == Q->rear)
printf("队列为空,无元素!\n");
else
{
printf("从队头起,队列中各元素为:");
while(p != Q->rear)
{
printf("%5d",Q->data[p]);
p++;
}
}
}
// 显示菜单子函数
void Menu()
{
printf("\n 顺序队列的各种操作");
printf("\n =================================================");
printf("\n| 1——初始化队列 |");
printf("\n| 2——判队空 |");
printf("\n| 3——判队满 |");
printf("\n| 4——求队列长度 |");
printf("\n| 5——入队操作 |");
printf("\n| 6——出队操作 |");
printf("\n| 7——求队头元素 |");
printf("\n| 8——显示队中所有元素 |");
printf("\n| 0——返回 |");
printf("\n =================================================");
printf("\n请输入菜单号(0-8):");
}
int main() {
int i, n, flag;
SeqQueue Q;
DataType x;
char ch1, ch2, a;
ch1 = 'y';
while (ch1 == 'y' || ch1 == 'Y') {
Menu();
scanf("%c", &ch2);
getchar();
switch (ch2) {
case '0':
ch1 = 'n';
break;
case '1':
InitQueue(&Q);
printf("队列的初始化完成!\n");
break;
case '2':
if (IsEmpty(&Q))
printf("队列为空!\n");
else
printf("队列不为空!\n");
break;
case '3':
if (IsFull(&Q))
printf("队列已满!\n");
else
printf("队列未满!\n");
break;
case '4':
printf("队列的长度为:%d\n", GetLength(&Q));
break;
case '5':
printf("请输入要入队的元素个数:");
scanf("%d", &n);
printf("请输入%d个入队的整数:", n);
for (i = 0; i < n; i++) {
scanf("%d", &x);
flag = EnQueue(&Q, x);
}
if (flag == 1)
printf("入队操作成功!\n");
else
printf("入队操作失败!\n");
break;
case '6':
printf("请输入要出队的元素个数:");
scanf("%d", &n);
printf("出队的元素顺序依次为:");
for (i = 0; i < n; i++) {
flag = DeQueue(&Q, &x);
printf("%5d", x);
}
if (flag == 1)
printf("\n出队操作成功!\n");
else
printf("\n出队操作失败!\n");
break;
case '7':
x = GetHead(&Q);
printf("当前的队头元素值为:%d\n", x);
break;
case '8':
ShowQueue(&Q);
break;
default:
printf("输入有误,请输入0-8进行选择!\n");
}
if (ch2 != '0') {
printf("\n按回车键继续,按任意键返回主菜单!\n");
a = getchar();
if (a != '\n') {
getchar();
ch1 = 'n';
}
}
}
return 0;
}
结语
循环顺序队列:
空队列 Q->front ==Q->rear
满队列 (Q->rear+1)%MAXSIZE
队长 (Q->rear -Q->front +MAXSIZE) %MAXSIZE
敬请各位大佬批评指正 日后也会持续更新数据结构相关内容,互相学习😊😊