和栈相反,队列是一种先进先出的的线性表。它只允许在表的一端进行插入,而在另一端删除元素。这和我们日常生活中的队列是一致的,最早进入队列的元素最早离开。在队列中,允许插入的一端叫做队尾,允许删除的一端则稀烂为队头。
顺序队列,即队列的顺序存储结构。由于队列的队头和队尾的位置均发生变化,因此在队列顺序存储结构中,除了用一组地址连续的存储单元依次存放从队头到队尾的元素之外,还需要附设两个指针front和rear指向队头和队尾元素。
为了操作方便,在此约定:在非空队列中,队头指针front始终指向队头元素,而队尾rear始终指向队尾元素下一个位置。
顺序队列的类型描述:
//顺序队列的类型描述
#define MAXSIZE 100
typedef int ElemType;
typedef struct{
ElemType *data;
int front,rear;
}SqQueue;
基本操作:
1. 初始化顺序队列Init_SqQueue(SqQueue* Q):
//初始化顺序队列
void Init_SqQueue(SqQueue* Q){
Q->data = (SqQueue*)malloc(sizeof(SqQueue) * MAXSIZE);
Q->front = Q->rear = 0;
}
2. 销毁顺序队列Destroy_SqQueue(SqQueue* Q)
//销毁顺序队列
void Destroy_SqQueue(SqQueue* Q){
if(Q->data){
free(Q->data);
Q->front = Q->rear = 0;
}
}
3. 清空顺序队列Clear_SqQueue(SqQueue* Q)
//清空顺序队列
void Clear_SqQueue(SqQueue* Q){
Q->front = Q->rear = 0;
}
4. 判断顺序队列是否为空IsEmpty_SqQueue(SqQueue* Q)
//判断顺序队列是否为空
int IsEmpty_SqQueue(SqQueue* Q){
if(Q->front == Q->rear)
return 1;
else{
return 0;
}
}
5. 判断顺序队列是否已满iSFull_SqQueue(SqQueue* Q)
//判断顺序队列是否已满
int iSFull_SqQueue(SqQueue* Q){
if(Q->rear == MAXSIZE)
return 1;
else
return 0;
}
因为没有设置额外的指针,所以这里判断顺序队列是否已满,实际上是假溢出,并不是真的顺序队列满,原因:
随着入队,出队的进行,整个队列会整体向后移动,这样就出现队尾指针已经移动到了最后,再有元素入队就会出现队满,即溢出,而事实上此时队中并未真正的满员,这种现象即称为“假溢出”。
6. 求得顺序队列的长度GetLength_SqQueue(SqQueue* Q)
//求得顺序队列的长度
int GetLength_SqQueue(SqQueue* Q){
return Q->rear - Q->front;
}
7. 取得顺序队列的的队头GetHead_SqQueue(SqQueue* Q,ElemType *x)
//取得顺序队列的的队头
void GetHead_SqQueue(SqQueue* Q,ElemType *x){
if(IsEmpty_SqQueue(Q)){
printf("顺序队列空!\n");
exit(0);
}
else{
*x = Q->data[Q->front];
}
}
8. 取得顺序队列的的队尾GetRear_SqQueue(SqQueue* Q,ElemType *x)
//取得顺序队列的的队尾
void GetRear_SqQueue(SqQueue* Q,ElemType *x){
if(IsEmpty_SqQueue(Q)){
printf("顺序队列空!\n");
exit(0);
}
else{
*x = Q->data[Q->rear - 1];
}
}
9. 入顺序队列En_SqQueue(SqQueue* Q,ElemType x)
//入顺序队列
void En_SqQueue(SqQueue* Q,ElemType x){
if(iSFull_SqQueue(Q)){
printf("顺序队列已满!\n");
exit(0);
}
else{
Q->data[Q->rear] = x;
Q->rear++;
}
}
10. 出顺序队列De_SqQueue(SqQueue* Q,ElemType *x)
//出顺序队列
void De_SqQueue(SqQueue* Q,ElemType *x){
if(IsEmpty_SqQueue(Q)){
printf("顺序队列空!\n");
exit(0);
}
else{
*x = Q->data[Q->front];
Q->front++;
}
}
11. 打印顺序队列Print_SqQueue(SqQueue* Q)
//打印顺序队列
void Print_SqQueue(SqQueue* Q){
int i = Q->front;
if(IsEmpty_SqQueue(Q)){
printf("顺序队列空!\n");
exit(0);
}
else{
while(i < Q->rear)
printf("%d\t",Q->data[i++]);
printf("\n");
}
}
说明:
以上这种顺序队列会出现“假溢出”,随着入队,出队的进行,整个队列会整体向后移动,这样就出现队尾指针已经移动到了最后,再有元素入队就会出现队满,即溢出,而事实上此时队中并未真正的满员。
为了能充分的利用空间,解决顺序队列的“假溢出”问题,可以采用两种方法:一种是将数据向前移动,让空的存储单元留在队尾;另一种是将顺序队列构造成一个环状的空间,即将队列的数据区data[0....MAXSIZE-1]看成头尾相接的循环结构,使得data[0]接在data[MAXSIZE-1]之后,这就是循环队列。