队列(queue)是只允许在一端进行插入操作、另一端进行删除操作的线性表。先进先出,插入端为队尾;删除端为队头。
队列作为一种特殊的线性表,也具有顺序结构和链式结构
循环队列:队列的头尾相接的顺序存储结构称为循环队列。使用循环队列是为了避免队列空间浪费、插入删除之后队头队尾指针操作不便等情况。
循环队列的顺秀结构如下:
//循环队列的顺序存储结构
typedef struct
{
QElemType data[MAXSIZE];
int front; //头指针,指向下标为0
int rear; //尾指针,若队列不为空,指向队尾元素的下一个位置
}SqQueue;
循环队列的头指针rear指向下标为0的位置,尾指针,指向最后一个元素的下一个位置。
注意:由于是循环队列,元素下标会因为循环而不断增加,但数组长度固定,因此计算队列中的元素个数、队列长度、判断是否队满等都需要对MAXSIZE取余。
①循环队列判断队满的条件:(rear+1)%MAXSIZE==front
②循环队列求队列长度:(rear-front +MAXSIZE)%MAXSIZE.
/************************************************************************/
/* 顺序队列 */
/************************************************************************/
#include
#include
#include
#include
#include
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 //存储空间初始分配量
typedef int Status;
typedef int QElemType; //队列元素的类型,此处定义为int
//循环队列的顺序存储结构
typedef struct
{
QElemType data[MAXSIZE];
int front; //头指针,指向下标为0
int rear; //尾指针,若队列不为空,指向队尾元素的下一个位置
}SqQueue;
Status visitSqQueue(QElemType c)
{
printf("%d",c);
return OK;
}
//初始化一个空的循环队列
Status InitQueue(SqQueue *Q)
{
Q->front =0;
Q->rear =0;
return OK;
}
//将队列Q清为空队列
Status ClearQueue(SqQueue *Q)
{
Q->front =Q->rear =0;
return OK;
}
//判断队列是否为空队列,若为空,返回TRUE;否则返回FALSE
Status isEmptyQueue(SqQueue Q)
{
if (Q.front==Q.rear)
return TRUE;
else
return FALSE;
}
//返回Q中元素的个数,即队列长度
int QueueLength(SqQueue Q)
{
return (Q.rear - Q.front + MAXSIZE)%MAXSIZE;
}
//若队列不为空,用e返回Q的队头元素,并返回OK;否则返回ERROR
Status GetHead(SqQueue Q, QElemType *e)
{
if (isEmptyQueue(Q))
return ERROR;
*e = Q.data[Q.front];
return OK;
}
//若队列未满,则插入元素e为Q的新的队尾元素
Status EnQueue(SqQueue *Q, QElemType e)
{
//首先要判断队满条件
if ((Q->rear+1)%MAXSIZE==Q->front)
return ERROR;
Q->data[Q->rear]=e;
Q->rear=( Q->rear+1)%MAXSIZE; //先给rear位置赋值,然后将rear指针后移一位,要考虑是循环队列,所以要对MAXSIZE取余
return OK;
}
//若队列不为空,删除队头元素用e表示
Status DeQueue(SqQueue *Q, QElemType *e)
{
if (Q->front==Q->rear)
return ERROR;
*e=Q->data[Q->front];
Q->front = (Q->front+1)%MAXSIZE;
return OK;
}
//从队头到队尾,一次对Q中的每个元素输出
Status QueueTraverse(SqQueue Q)
{
int i=Q.front;
while(i!=Q.rear)
{
printf("%d ",Q.data[i]);
i=(i+1)%MAXSIZE;
}
printf("\n");
return OK;
}
int main()
{
Status j;
int i=0;
int l;
QElemType d;
SqQueue Q;
InitQueue(&Q);
printf("初始化队列后,队列是否为空?%u(1:空;0:否)\n",isEmptyQueue(Q));
printf("请输入整型队列元素(不超过%d个),-1为提前结束符\n",MAXSIZE-1);
do
{
d=i+100;
if (d==-1)
break;
i++;
EnQueue(&Q,d);
} while (i1);
printf("队列长度为:%d\n",QueueLength(Q));
printf("初始化队列后,队列是否为空?%u(1:空;0:否)\n",isEmptyQueue(Q));
QueueTraverse(Q);
printf("连续%d次由队头删除元素,队尾插入元素:\n",MAXSIZE);
for (l=1;l<=MAXSIZE;l++)
{
DeQueue(&Q,&d);
printf("删除的元素是%d,插入的元素是%d\n",d, l+1000);
d=l+1000;
EnQueue(&Q, d);
}
printf("连续插入和删除之后,现在队列长度为%d\n",QueueLength(Q));
QueueTraverse(Q);
printf("共向队尾插入了%d个元素\n",i+MAXSIZE);
if (l-2>0)
{
printf("现在由队头插入了%d个元素\n",l-2);
}
j=GetHead(Q,&d);
if (j)
{
printf("现在的队头元素为:%d\n",d);
}
ClearQueue(&Q);
printf("初始化队列后,队列是否为空?%u(1:空;0:否)\n",isEmptyQueue(Q));
getchar();
}
链队列是一种特殊的链式存储的线性表。只能尾进头出。
①有头结点,②front指针指向头结点;③rear指针指向最后一个结点。④若是空的链队列,则只有头结点,且front和rear指针同时指向头结点。
链队列结构中,除了链表的基本结构定义,链队列结构中,仅包含链表结构的front和rear指针。
//定义链队列结构
struct QNode
{
QElemType data;
struct QNode *next;
};
typedef struct QNode QNode;
typedef struct QNode* QueuePtr;
typedef struct
{
QueuePtr front; //只需定义链队列的头指针和尾指针
QueuePtr rear;
}LinkQueue;
/************************************************************************/
/* 链队列:队列的链式存储结构 */
/************************************************************************/
//定义链队列结构
struct QNode
{
QElemType data;
struct QNode *next;
};
typedef struct QNode QNode;
typedef struct QNode* QueuePtr;
typedef struct
{
QueuePtr front; //只需定义链队列的头指针和尾指针
QueuePtr rear;
}LinkQueue;
Status visitLinkQueue(QElemType c)
{
printf("%d ",c);
return OK;
}
//构造一个空的链队列
Status InitLinkQueue(LinkQueue *Q)
{
QueuePtr head=(QueuePtr)malloc(sizeof(QNode));
Q->front=Q->rear = head;
if (!Q->front)
{
exit(OVERFLOW); //如果front指针为空,退出
}
Q->front->next=NULL;
return OK;
}
//销毁链队列Q ,链表指针之间有相互关系(注意链队列是尾进头出,因此消除的时候从头部开始)
Status DestroyLinkQueue(LinkQueue *Q)
{
while(Q->front)
{
Q->rear=Q->front->next;
free(Q->front);
Q->front=Q->rear;
}
return OK;
}
//将Q清空为空链队
Status ClearLinkQueue(LinkQueue *Q)
{
QueuePtr p,q;
Q->rear=Q->front;
p=Q->front->next;
Q->front->next=NULL;
while(p)
{
q=p;
p=p->next;
free(q);
}
return OK;
}
//若链队列为空,返回TRUE;否则返回FALSE
Status isLinkQueueEmpty(LinkQueue Q)
{
if (Q.front==Q.rear)
return TRUE;
else
return FALSE;
}
//求链队列的长度
int LinkQueueLength(LinkQueue Q)
{
QueuePtr p;
p=Q.front;
int count=0;
while(p!=Q.rear)
{
count++;
p=p->next;
}
return count;
}
//若链队列不为空,用e返回Q的队头元素,并返回OK;否则返回ERROR
Status GetHead(LinkQueue Q, QElemType *e)
{
if (Q.front==Q.rear)
return ERROR;
*e=Q.front->next->data;
return OK;
}
//插入元素e为Q的新的队尾元素
Status EnLinkQueue(LinkQueue *Q,QElemType e)
{
QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
if (!p)
exit(OVERFLOW); //若存储分配失败,则退出
p->data=e;
p->next=NULL;
Q->rear->next=p;
Q->rear=p;
return OK;
}
//若队列不为空,删除Q的队头元素e返回其值,并返回OK;否则,返回ERROR
Status DeQueue(LinkQueue *Q, QElemType *e)
{
if (Q->front ==Q->rear)
return ERROR;
QueuePtr p; //需要新建一个指针,后面还有free释放掉
p=Q->front->next;
*e=p->data;
Q->front->next=p->next;
//判断尾指针是否为p,若相等,尾指针特殊处理;否则直接释放就可以
if (Q->rear==p)
Q->rear=Q->front;
free(p);
return OK;
}
//从队头到队尾依次对每个元素输出
Status LinkQueueTraverse(LinkQueue Q)
{
QueuePtr p;
p=Q.front->next; //p初始化,指向第一个结点
while(p)
{
visitLinkQueue(p->data);
p=p->next;
}
printf("\n");
return OK;
}
int main()
{
int i;
QElemType d;
LinkQueue q;
i=InitLinkQueue(&q);
if (i)
printf("成功构建一个空的链队列。\n");
printf("是否为空的链队列?%d(1:空;0:否)\n",isLinkQueueEmpty(q));
printf("链队列长度为:%d\n",LinkQueueLength(q));
LinkQueueTraverse(q);
EnLinkQueue(&q,-5);
EnLinkQueue(&q,5);
EnLinkQueue(&q,10);
printf("插入3个元素之后,链队列长度为:%d\n",LinkQueueLength(q));
LinkQueueTraverse(q);
DeQueue(&q,&d);
printf("%d\n",d);
LinkQueueTraverse(q);
getchar();
}