队列:先进先出的线性表,FIFO,只允许在一端(队尾)进行插入操作,而在另一端(队头)进行删除操作的线性表。
队列抽象数据类型:
ADT 队列(Queue)
Data
同线性表。元素具有相同的类型,相邻元素具有前驱和后继的关系。
Operation
InitQueue(*Q):初始化操作,建立一个空队列Q
DestroyQueue(*Q):若队列Q存在,则销毁它。
ClearQueue(*Q):清空队列Q
QueueEmpty(*Q):若队列Q为空,返回true,否则返回false
GetHead(Q,*e):若队列Q存在且非空,用e返回队列Q的队头元素
EnQueue(*Q,e):若队列Q存在,插入新元素e到队列Q中并成为队尾元素。
DeQueue(*Q,*e):删除队列Q中队头元素,并用e返回其值。
QueueLength(Q):返回队列Q的元素个数。
endADT
队尾插入、队头删除。
队列顺序存储
1.头指针front(指向队头元素)、尾指针rear(指向队尾元素下一个位置),通过头指针移动实现出队列,队头元素不需要移动,头指针后移,相当于前一个元素出队列。
2.front、rear重合,意味着队列变成空队列,而不是还有一个元素。
循环队列
头尾相接:改变尾指针的指向
改善假性溢出的问题
判断队列满
最大尺寸:QueueSize,队列满条件:(rear+1)%QueueSize==front
计算队列长度的通用公式:(rear-front+QueueSize)%QueueSize
循环队列的顺序存储结构代码;
typedef int QElemType
typedef struct
{
QElemType data [MAXSIZE];
int front ;
int rear ;
}SqQueue;
初始化:
Status InitQueue(SqQueue *Q)
{
Q->front=o;
Q=->rear=0;
return OK;
}
循环队列求队列长度代码:
int QueueLength(SqQueue Q)
{
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
循环队列的入队列操作代码:
Status EnQueue (SqQueue *Q,QelemType e)
{
if ((Q->rear+1)%MAXSIZE==Q->front)
return ERROR;
Q->data[Q->data[Q->rear]=e;
Q->rear=(Q->rear+1)%MAXSIZE;
return OK;
}
出队列:
Status DeQueue(SqQueue *Q,*e)
{
if (Q->rear==Q->front)
return ERROR;
*e=Q->data[Q->front];
Q->front=(Q->front+1)%MAXSIZE;
return OK;
}
解析——————----————----------------
建立循环队列的顺序存储结构
一个结构体 名字是SqQueue、后面又赋给Q队列
里面有三个元素:
1.data数组存放队列元素的值
2.front 是头指针
3.rear 是尾指针
看到:Q.rear/Q->rear,是调用结构体两个指针值,看它们指向哪?这个和队列的元素值没关系,只和宏观队列的长度、队头、队尾位置有关
Q->data[ ],是队列中的元素的值,Q->data[ Q->rear],是指队尾元素的值
队列链式存储
只能尾进头出的单链表
正常链表两边都可以添加或者删除,队列链表只能在一段添加,另一端删除。
front 指向链表头结点
rear指向链表终端结点
空队列:front和rear都指向头结点
typedef int QElemType;
typedef struct QNode//结点结构
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct //队列链表结构
{
QueuePtr front, rear;
}LinkQueue;
入队操作;