一、队列的概念
队列是一种特殊的线性表,严格按照“先进先出”的原则。
二、队列基础
队列和栈一样只允许在断点处插入和删除元素,其基本操作包括以下:
(1)InitQueue(&Q); //初始化一个空队列
(2)DestroyQueue(&Q); //清空队列
(3)QueueEmpty(&Q); //队列判空
(4)QueueLength(&Q); //求队列的长度
(5)GetHead(Q,&e); //取对头元素
(6)EnQueue(&Q,e); //插入新元素
(7)DeQueue(&Q,&e); //删除队头元素
(8)QueueTraverse(Q,visit()); //每个元素调用visit()函数
队列的分类:链队列和循环队列
C语言定义链队的格式
typedef struct QNode { ElemType data; struct Qnode *next; }QNode,*QueuePtr; typedef struct { QueuePtr front; //对头指针,指向头元素 QueuePtr rear; //队尾指针,指向队尾元素 }LinkQueue;
可以采用顺序表来存储定义循环队列,具体代码如下:
#define MAXQSIZE 100 //最长队列长度 typedef struct { ElemType *base; //存储空间 int front; //头指针,指向队列的头元素 int rear; //尾指针,指向队列元素的下一个位置 }SqQueue;
队列的基本操作
(1)初始化队列Q的目的是创建一个队列
void InitQueue(QUEUE *Q) { Q->front = -1; Q->rear = -1; }
(2)入队的目的是将一个新元素添加到队尾,相当于队列最后队列等候。
void EnQueue(QUEUE *Q, Elemtype elem){ if ((Q->rear+1)%MAX_QUEUE==Q->front) { exit(OVERFLOW); } else{ Q->rear = (Q->reasr + 1) % MAX_QUEUE; Q->elem[Q->rear] = elem; } }
(3)出队的目的是取出对头元素,并同时删除该元素,使后一个元素成为对头元素。
void DeQueue(QUEUE *Q, Elemtype *elem) { if (QueueEmpty(*Q)) { exit("Queue is empty."); } else { Q->front = (Q->front + 1) % MAX_QUEUE; *elem = Q->elem[Q->front]; } }
(4)获取队列的第一个元素,即将队头的元素取出,不删除该元素,队头仍然是该元素。
void GetFront(QUEUE *Q, Elemtype *elem) { if (QueueEmpty(*Q)) { exit("Queue is empty."); } else { *elem = Q->elem[ (Q->front + 1) % MAX_QUEUE]; } }
(5)判断队列Q是否为空
int QueueEmpty(Queue Q) { if (Q.front==Q.rear) { return TRUE; } else { return FALSE; } }
队列的链式存储
在C语言中,链式队列的基本操作算法如下:
(1)初始化队列Q,算法代码如下:
void InitQueue(QUEUE *Q) { Q->front = (LINKLIST*)malloc(sizeof(LINKLIST)); if (Q->front==NULL) { exit(ERROR); } Q->rear = Q->front; }
(2)入队操作
void EnQueue(QUEUE *Q, Elemtype elem){ s = (LINKLIST*)malloc(sizeof(LINKLIST)); if (!s) { exit(ERROR); } s->elem = elem; s->next = NULL; Q->rear->next = s; Q->rear = s; }
(3)出队操作
void DeQueue(QUEUE *Q, Elemtype *elem) { if (QueueEmpty(*Q)) { exit(ERROR); } else { *elem = Q->front->next->elem; s = Q->front->next; Q->front->next = s->next; Q->front = (Q->front + 1) % MAX_QUEUE; free(s); } }
(4)获取队头元素
void GetFront(QUEUE Q, Elemtype *elem) { if (QueueEmpty(Q)) { exit(ERROR); } else { *elem = Q->front->next->elem; } }
(5)判断队列Q是否为空
void QueueEmpty(QUEUE Q) { if (Q->front==Q->rear) { return TRUE; } else { return FALSE; } }
三、实例演练
“新增顾客”编号问题
代码实现:
/* 构建一个完整循环队列 */ #include "stdio.h" #include "malloc.h" #define QUEUEMAX 15 //typedef DATA; typedef struct { DATA data[QUEUEMAX]; //队列数组 int head; int tail; }CycQueue; CycQueue *CycQueueInit() { CycQueue *q; if (q=(CycQueue *)malloc(sizeof(CycQueue))) { q->head = 0;//设置队头 q->tail = 0;//设置队尾 return q; } else { return NULL;//返回空 } } void CycQueueFree(CycQueue *q) //释放队列 { if (q!=NULL) free(q); } int CycQueueIsEmpty(CycQueue *q) //队列是否为空 { return (q->head == q->tail); } int CycQueueIsFull(CycQueue *q) //队列是否为满 { return ((q->tail + 1) % QUEUEMAX == q->head); } int CycQueueIn(CycQueue *q, DATA data) //入队 { if ((q->tail + 1) % QUEUEMAX == q->head) { printf("队列满了!\n"); return 0; } else { q->tail = (q->tail + 1) % QUEUEMAX;//求列尾序号 q->data[q->tail] = data; return 1; } } DATA *CycQueueOut(CycQueue *q) //循环队列出队函数 { if (q->head==q->tail) //队列为空 { printf("队列为空了!\n"); return NULL; } else { q->head = (q->head + 1) % QUEUEMAX; return &(q->data[q->head]); } } int CycQueueLen(CycQueue *q) //获取队列长度 { int n; n = q->tail - q->head; if (n<0) { n = QUEUEMAX + n; } return n; } DATA *CycQueuePeek(CycQueue *q) //获取队列第一个位置的数据 { if (q->head==q->tail) { printf("队列已经空了!\n"); return NULL; } else { return &(q->data[(q->head + 1) % QUEUEMAX]); } } ############################################## #include "stdlib.h" #include "stdio.h" #include "time.h" #include "xuncao.h" typedef struct { int num; //顾客编号 long time; //进入队列的时间 }DATA; int num; //顾客序号 void add(CycQueue *q) //新增顾客排列 { DATA data; if (!CycQueueIsFull(q)) { data.num = ++num; data.time = time(NULL); CycQueueIn(q, data); } else { printf("\n排队的人实在是太多了,请您稍候再排队!\n"); } } void next(CycQueue *q) //通知下一位顾客准备 { DATA *data; if (!CycQueueIsEmpty(q)) //若队列不为空 { data = CycQueueOut(q); //取队列头部的数据 printf("\n欢迎编号为%d的顾客到柜台办理业务!\n", data->num); } if (!CycQueueIsEmpty(q)) //若队列不为空 { data = CycQueuePeek(q); //取队列中指定位置的数据 printf("请编号为%d的顾客做好准备,马上将为您办理业务!\n", data->num); } } int main() { CycQueue *queuel; int i, n; char select; num = 0; //顾客序号 queuel = CycQueueInit();//初始化队列 if (queuel==NULL) { printf("创建队列时出错误!\n"); getch(); return 0; } do { printf("\n请选择具体操作:\n"); printf("1.新到顾客\n"); printf("2.下一个顾客\n"); printf("0.退出\n"); fflush(stdin); select = getch(); switch (select) { case'1': add(queuel); printf("\n现在共有%d位顾客在等候!\n", CycQueueLen(queuel)); break; case'2': next(queuel); printf("\n现在共有%d位顾客在等候!\n", CycQueueLen(queuel)); break; case'0': break; } } while (select!='0'); CycQueueFree(queuel); //释放队列 system("pause"); return 0; }