队列是一种只允许在表的一端(称为队尾)进行插入,而在另一端(称为队头)进行删除的线性表,是线性表的一种特例。
顺序队列是用数组结构来表示的。为了描述队列的这种结构,我们需要两个表明队头和队尾的指针,规定队头指针指向队列头结点的前一个位置,而队尾指针指向队列的尾结点。而为什么又会用到循环队列呢,因为为了防止“假上溢”对空间造成的浪费。“假上溢”是这么来的,先说“上溢”和“下溢”。下溢就是当空对时,如果再做出队操作,则会产生“下溢”。
当队满时,再做入对操作会产生“上溢”。但是,如果当前尾指针等于数组的上界,即使队列不满,再做入队操作也会引起溢出。这种现象就是“假上溢”。然而有了循环队列,我们就可以避免假上溢的问题了。但是循环队列还是有一个问题,就是判断队列与队满的情况。如果按照前面的规定,队头指针指向队列头结点的前一个位置,而队尾指针指向队列的尾结点。那么是分辨不出来队满与队空的关系的。我看书中列出了3种解决此问题的方法。不过第三种最适合,它是采用少用一个节点空间,即头指针指向的空间不使用。这样的话。当front等于rear时,队空;入队后,当尾指针加1后等于头指针,即:(rear+1)%maxsize = front.则说明这时队列已满。
下面是对循环顺序队列操作的一个整体代码:
#include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 typedef struct node { int data[MAXSIZE]; int front; //存放队列头地址 int rear; //存放队列尾地址 }sequeue; void Sequeue_SetNull(sequeue *q); //队列置空 int Sequeue_Empty(sequeue *q); //判断队列是否为空 int Sequeue_GetFront(sequeue *q); //得到队列头结点 int Sequeue_In(sequeue *q, int dat); //入对操作 int Sequeue_Out(sequeue *q); //出队操作 void ShowSequeue(sequeue *q); //输出显示队列 int main(void) { int num, i, dat, choice, ans; sequeue *q; q = (sequeue*)malloc(sizeof(sequeue)); printf("循环顺序队列的操作练习:\n"); printf("输入你想创建队列的数据个数:\n"); scanf("%d", &num); if(num>MAXSIZE-1) { printf("队列结点数大于最大允许空间!\n"); return 0; } Sequeue_SetNull(q); printf("请依次输入队列数据:\n"); for(i=1; i<num+1; i++) //循环输入队列结点数据 { scanf("%d", &dat); q->data[i] = dat; q->rear = i; } while(1) { printf("队列操作:\n"); printf("1.取队列结点\n"); printf("2.入队操作\n"); printf("3.出队操作\n"); printf("4.输出队列\n"); printf("5.退出程序\n"); printf("做出选择:\n"); scanf("%d", &choice); switch(choice) { //取队列头结点 case 1: dat = Sequeue_GetFront(q); printf("头结点为:%d\n", dat); break; //入队 case 2: printf("输入你想入队的数据:\n"); scanf("%d", &dat); ans = Sequeue_In(q, dat); if(ans) printf("入队成功!\n"); else printf("入队失败!\n"); break; //出队 case 3: ans = Sequeue_Out(q); if(ans) printf("出队成功!\n"); else printf("出队失败!\n"); break; //输出显示队列 case 4: ShowSequeue(q); break; //退出程序 case 5: return 0; break; default: printf("选择无效!\n"); break; } } } //队列置空 void Sequeue_SetNull(sequeue *q) { q->rear = 0; //其中数组第一个节点空间不使用(即下标为0数组元素),用作队列满与空的区别 q->front = 0; } //判断队列是否为空 int Sequeue_Empty(sequeue *q) { if(q->front == q->rear) //头结点等于尾结点即表示队列为空 return 1; else return 0; } //取得队列头结点 int Sequeue_GetFront(sequeue *q) { if(Sequeue_Empty(q)) //取头结点先要判断队列是否为空 { printf("队列空!\n"); return 0; } else return q->data[(q->front+1) % MAXSIZE]; } //入队 int Sequeue_In(sequeue *q, int dat) { if((q->rear+1)%MAXSIZE == q->front) //入队先要判断队列是否已经满了 return 0; else { q->rear = (q->rear+1) % MAXSIZE; //使用求模运算 q->data[q->rear]= dat; return 1; } } //出队 int Sequeue_Out(sequeue *q) { if(Sequeue_Empty(q)) //出队先要判断队列是否为空 return 0; else { q->front = (q->front+1) % MAXSIZE; //求模运算 return q->data[q->front]; } } //输出显示队列 void ShowSequeue(sequeue *q) { int i; i = q->front+1; while(i != q->rear+1) { printf("%d ", q->data[i]); i++; } printf("\n"); }