队列是线性表的子类,其特点是只准队尾进,队头出,这个特点与实际生活中的排队一样,当然这里是
不准插队的,如图所示:
具体代码以及注解如下程序:
#include <stdio.h> #include <stdlib.h> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ //定义队列长度 #define QUENE_MAXSIZE 10 //队列节点的数据类型 typedef struct{ int a; }ElementType; //队列的特性是队头出,队尾进,与堆栈类似的用2个指针分别指向队头与队尾 //队列的数据结构(顺序队列) typedef struct { //循环队列要确定一个基础地址 ElementType* base; //循环队列其实是队数组指针下标的操作来实现的 int rear; int front; }Quene,*QueneP; //初始化一个空队列,队列为空的条件头指针指向尾指针 //但是在实际应用过程中,这样的结构会出现一个问题,队列的长度有限, //如果顺序存储结构的队列会出现超出数组范围的问题。所以这里我们实际 //创建一个循环队列,但是注意的是实际上队列的存储空间还是线性的,并没有 //头尾相连,这里实现循环的效果主要是利用取余运算的特性来实现数组下标的访问。 //而循环队列判断队列空的方法有2个:1、多余留出一个空间,来区别队满的时候rear==front与 // 队空的时候rear == front; // 2、利用一个标志位Tag来判断队空队满。 //初始化一个空队列 int initQuene(QueneP q) { q->base = (ElementType*)malloc(QUENE_MAXSIZE*sizeof(ElementType)); if(!q->base)return -1; q->front = q->rear = 0;//队列置空,这里利用第一种方式来判断队列的空与满,也就是预留一个空间 return 0; } //出队,从队头获取数据,注意这里的队头下标操作是++; int DeQuene(QueneP q,ElementType* data) { //判断队空 if(q->rear == q->front){ printf("队已空 "); return -1; } *data = q->base[q->front]; printf("出队front:%d ",q->front); q->front = (q->front+1)%QUENE_MAXSIZE; return 0; } //进队,从队尾添加数据,注意这里下标操作也是++ int EnQuene(QueneP q,ElementType* data) { //判断队满,这里是循环队列理解的一个相对难点。 //所谓预留空间来判断队满,具体的实现就是(q->rear+1) //因为取余运算的结果范围是(0,QUENE_MAXSIZE) ,所以 // 当rear指向队列最大长度的位置时,在移动一位就回到了 //队列的头,这个时候说明队列是满的。 if((q->rear+1)%QUENE_MAXSIZE==q->front){ printf("队已满 "); return -1; } printf("进队rear:%d ",q->rear); q->base[q->rear] = *data; q->rear = (q->rear+1)%QUENE_MAXSIZE; return 0; } int main(int argc, char *argv[]) { int i; Quene quene; ElementType et; ElementType temp; initQuene(&quene); for(i=0;i<QUENE_MAXSIZE;i++){ et.a = i+3; EnQuene(&quene,&et); } for(i=0;i<QUENE_MAXSIZE;i++){ DeQuene(&quene,&temp); printf("data:%d ",temp.a); } system("pause"); return 0; }
注意上述程序的结构图如下: