和栈相反,队列是一种先进先出的的线性表。它只允许在表的一端进行插入,而在另一端删除元素。这和我们日常生活中的队列是一致的,最早进入队列的元素最早离开。在队列中,允许插入的一端叫做队尾,允许删除的一端则稀烂为队头。
顺序队列,即队列的顺序存储结构。由于队列的队头和队尾的位置均发生变化,因此在队列顺序存储结构中,除了用一组地址连续的存储单元依次存放从队头到队尾的元素之外,还需要附设两个指针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]之后,这就是循环队列。