队列类型定义
有关队列的相关概念,可以参考数据结构之线性表(十一)——栈和队列的定义和特点。
抽象类型定义如下:
ADT Queue
{
数据对象:
D
=
{
a
i
∣
a
i
∈
E
l
e
m
S
e
t
,
i
=
1
,
2
,
.
.
.
,
n
,
n
≥
0
}
D=\{a_i|a_i \in ElemSet,i=1,2,...,n,n\geq 0 \}
D={ai∣ai∈ElemSet,i=1,2,...,n,n≥0}
数据关系:
R
=
{
<
a
i
−
1
,
a
i
>
∣
a
i
−
1
,
a
i
∈
D
,
i
=
1
,
2
,
.
.
.
,
n
}
R=\{<a_{i-1},a_i>|a_{i-1},a_i \in D,i=1,2,...,n\}
R={<ai−1,ai>∣ai−1,ai∈D,i=1,2,...,n}
约定其中
a
1
a_1
a1端为队头,
a
n
a_n
an端为队尾。
基本操作: 有初始化,获取队头元素等操作。
}ADT Queue
顺序队
队列的存储方式也有两种:顺序队列和链式队列。
顺序队列的表示——用一维数组base[MAXQSIZE]
#define MAXQSIZE 100 //队列的最大长度
typedef struct
{
QElemType* base; //初始化的动态分配存储空间
int front; //头指针,即队头元素下标
int rear; //尾指针,即队尾元素下标
};
表示和实现:
-
新建一个空队列,初始情况为:
front=rear=0
-
有元素入队:
base[rear]=x;rear++;
,例如J1,J2,J3入队
-
有元素出队:
x=base[front];front++;
,例如J1,J2出队
空队标志:```front==rear````
- 接着上一个的状态,让J4,J5,J6入队,J3,J4出队,如下图,
那么,此时,还可以入队吗?
此时,就发生了问题,即当rear=MAXQSIZE时,发生了溢出。
溢出分两种情况:
- 真溢出:若front=0,rear=MAXQSIZE时,再入队,
这种情况下,该队列确实没有空间存放元素了,所有位置都放满了。 - 假溢出:
f
r
o
n
t
≠
0
front \neq0
front̸=0,rear=MAXQSIZE时,再入队,
这种情况下,该队列并没有满,该队列其实是有存储空间的。
所以,怎么解决假溢出的这种情况呢?
-
方式一.与现实生活中的排队类似,队头每离开一个元素,剩下的所有元素都往前移一位。
但是,这种方式有明显的缺点:浪费时间,因为每移动一次,队中元素都要移动。 -
方式二.引入循环顺序队
将队空间设想成一个循环的表,即分配给队列的m个空间循环使用,当rear=MAXQSIZE时,若向量的开始端空着,就可以从头使用空着的空间。当front为MAXQSIZE时,也是一样。
base[0]要接在base[MAXQSIZE]之后,若rear+1==M,则令rear=0;
实现方法:利用模运算。
插入元素:Q.base[Q.rear]=x;Q.rear=(Q.rear+1)%MAXQSIZE;
删除元素:x=Q.base[s.front];Q.front=(Qfront+1)%MAXQSIZE;
循环顺序队
在循环顺序队里,队空和队满的标志都是front==rear
,如下图,
如何判断循环顺序队的队空或队满?一般有三种方法:
- 另外设一个标志以区别队空,队满
- 另外设一个变量,记录元素个数
- 少用一个元素空间
这里,可以采用第三种——少用一个元素空间。
- 一般情况如下图,
- 而少用一个元素空间为:
此时,判断队满的标志是:(rear+1)%MAXQSIZE==front。
循环队列里的各项操作
- 循环队列初始化
Status InitQueue(SqQueue& Q)
{
Q.base = new QElemType[MAXQSIZE]; //分配数组空间
if (!Q.base)
exit(OVERFLOW); //存储分配失败
Q.front = Q.rear = 0; //头指针尾指针设为0,队列为空
return OK;
}
- 求循环队列的长度
int QueueLength(SqQueue Q)
{
return ((Q.rear - Q.front + MAXQSIZE) % MAXQSIZE);
}
- 循环队列入队
Status EnQueue(SqQueue& Q, QElemType e)
{
if ((Q.rear + 1) % MAXQSIZE == front) //队满
return ERROR;
Q.base[Q.rear] = e; //新元素加入队尾
Q.rear = (Q.rear + 1) % MAXQSIZE; //队尾指针加1
return OK;
}
- 循环队列出队
Status EnQueue(SqQueue& Q, QElemType& e)
{
if (Q.front == Q.rear) //队空
return ERROR;
e = Q.base[Q.front]; //保存队头元素
Q.front = (Q.front + 1) % MAXQSIZE; //队头指针加1
}
- 循环队列取队头元素
SElemType GetHead(SqQueue Q)
{
if (Q.front != Q.rear) //队列不为空
return Q.base[Q.front]; //返回队头指针元素的值,队头指针不变
}