队列
- 队列(Queue):插入在表一端进行,删除在表的另一端进行的线性表。
- 队尾(rear):允许插入的一端
- 队头(front):允许删除的一端
- 空队:不含数据元素的队列
- 入队(In):插入元素
- 出队(Out):删除元素
特点:先进先出(FIFO)
顺序队
思考
如何改造数组实现队列的顺序存储?
答:设置对头、队尾两个指针。约定:front指向队头的前一个位置,rear指向对尾。
描述顺序队需要几个属性?
- 存储空间的起始位置:data
- 存储容量:MaxSize
- 当前队尾的位置:rear
- 当前队头的位置:front
说明
1、
若 把顺序队列定义为:SeQueue *sq;
则 申请顺序队存储空间:sq = new SeQueue;
队列的数据区:sq->data[0]…sq->data[MaxSize - 1]
队尾元素表示为:sq->data[sq->rear]
队头元素表示为:sq->data[sq->front + 1]
2、队头、队尾与队中元素的关系;
入队:队尾指针加1 sq->rear++;
出队:队头指针加1 sq->front++
队空条件:sq->rear = = sq->front
队满条件:sq->rear = = MaxSize - 1
假溢现象
当顺序队一直入队,再出队,再有元素插入时,就会被插入数组下标最大的位置上之后,队列的空间用完,此时数组的低端还要空闲空间,这就出现了假溢现象。
如何解决假溢现象?
将队列数据区data[0]…data[MaxSize - 1]看成头尾相接的循环结构,头尾指针关系不变——循环队列
不存在物理的循环结构,用软件方法实现。
求模:((MaxSize - 1) + 1) % MaSize == 0
循环队列
入队:rear = (rear + 1) % MaxSize
出队:front = (front + 1) % MaxSize
队空条件:front = rear ➡num = 0;
队满条件:(rear + 1) % MaxSize = front ➡ num =MaxSize
循环队列基本操作
循环队列数据类型定义
typedef struct{
DataType data[MaxSize];
int front, rear;
int num;
}C_SeQueue;
循环队列初始化
C_SeQueue *Init_C_SeQueue()
{
C_SeQueue *q;
q = new C_SeQueue;
q->rear = 0;
q->front = 0;
return q;
}
循环队列判断队空
int Empty_SeQueue(C_SeQueue *q)
{
if(q->rear == q->front)
return 1;
else
return 0;
}
循环队列判断队满
int Full_C_SeQueue(C_SeQueue *q)
{
if((q->rear + 1) % MaxSize == q->front)
return 1;
else
return 0;
}
循环队列插入算法
int In_C_SeQueue(C_SeQueue *q, DataType x)
{
if(Full_C_SeQueue(q))
return 0;
else
{
q->rear = (q->rear + 1) % MaxSize;
q->data[q->rear] = x;
return 1;
}
}
循环队列出队算法
int Out_C_SeQueue(C_SeQueue *q, DataType *x)
{
if(Empty_C_SeQueue(q))
return 0;
else
{
x = q->data[q->rear];
q->front = (q->front + 1) % MaxSize;
return 1;
}
}
链队
从结构上考虑,将队头、队尾指针封装在一个结构体中.
表头作为队头,表尾作为队尾。
习惯采用带头结点的形式。
链队的结构体
typedef struct{
DataType data;
struct node *next;
}QNode;
typedef struct{
QNode *front,*rear;
}LQueue;
链队的初始化
LQuquq *Init_LQueue(){
LQueue *q;
QNode *p;
q = new LQueue;
p = new QNode;
q->front = q->rear = p;
p->next = NULL;
return q;
}
链队入队算法
void In_LQueue(LQueue *q,DataType x)
{
Qnode *p;
p = new QNode;
p->data = x;
p->next = NULL;
q->rear->next = p; //将新结点插入队尾
q-rear = p; //队尾指针指向新结点
}
链队的删除算法
int Out_LQueue(LQueue *q, DataType *x)
{
QNode *p;
if(Empty_LQueue(q))
return 0;
else
{
p = q->front->next;
q->front->next = p->next;
x = p->data;
delete(p);
if(q->front->next == NULL) //若队列中只有一个元素时,出队后表为空
q->rear = q->front;
return 1;
}
}