数据结构之队列
队列是一种先进先出(FIFO)的数据结构,下面是循环队列顺序存储方式
#include<stdio.h>
#include<stdlib.h>
#include<io.h>
#include<math.h>
#include<time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20
typedef int Status;
typedef int QElemType;
// 循环队列的顺序结构
typedef struct{
QElemType data[MAXSIZE];
int front;
int rear;
}SqQueue;
Status visit(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;
}
//判断是否为空
Status QueueEmpty(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返回队列的队头元素
Status GetHead(SqQueue Q, QElemType *e){
if(Q.front == Q.rear)
return ERROR;
*e = Q.data[Q.front];
return OK;
}
//插入新的元素e
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;
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;
}
//从队头到队尾依次输出
Status QueueTraverse(SqQueue Q){
int i;
i = Q.front;
while((i + Q.front) != Q.rear){
visit(Q.data[i]);
i = (i + 1) % MAXSIZE;
}
printf("\n");
return OK;
}
int main(){
Status j;
int i = 0, l;
QElemType d;
SqQueue Q;
InitQueue(&Q);
//%u表示无符号的十进制整数
printf("初始化队列后,队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
printf("请输入整型队列元素(不超过%d个),-1为提前结束符: ",MAXSIZE-1);
do{
d = i + 100;
if(d == -1)
break;
i++;
EnQueue(&Q,d);
}while(i < MAXSIZE - 1);
printf("队列长度为: %d\n",QueueLength(Q));
printf("现在队列空否?%u(1:空 0:否)\n",QueueEmpty(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);
}
l = QueueLength(Q);
printf("现在的队列元素为:\n");
QueueTraverse(Q);
printf("共向队尾插入了%d个元素\n",i+MAXSIZE);
if(l - 2 > 0)
printf("现在由队头删除了%d个元素\n",l - 2);
while(QueueLength(Q)>2){
DeQueue(&Q,&d);
printf("删除的元素为%d\n",d);
}
j = GetHead(Q,&d);
if(j)
printf("现在队头元素为:%d\n",d);
ClearQueue(&Q);
printf("清空队列后,队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
return 0;
}
下面是链队列的代码方式
#include<stdio.h>
#include<stdlib.h>
#include<io.h>
#include<math.h>
#include<time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20
typedef int Status;
typedef int QElemType;
typedef struct QNode //用于定义链的结点
{
QElemType data;//定义结点的数据域
struct QNode *next;//定义 结点的指针域
}QNode,*QueuePtr;//定义一个可以定义结点的名称,定义一个指 向结点的指针
typedef struct //定义链表的结构,包含两个结点指针
{
QueuePtr front,rear;
}LinkQueue;
Status visit(QElemType c)//用于访问结点的数据域
{
printf("%d ",c);
return OK;
}
/* 构造一个空队列Q */
Status InitQueue(LinkQueue *Q)
{
Q->front=Q->rear=(QueuePtr)malloc(sizeof(QNode));
//申请大小为结点结构的动态空间,第一个括号为指向结点指针,第二个括号为结点大小
if(!Q->front)
exit(OVERFLOW);
//xit(OVERFLOW)的含义就是,退出程序,并返回OVERFLOW的值给主调进程。
//其标准的使用范围为,当程序运算出现上溢时,退出程序并报错给主调进程。
Q->front->next=NULL;//头指针为栈顶
return OK;
}
/* 销毁队列Q,就是什么都没有了 ,头结点都释放掉了*/
Status DestroyQueue(LinkQueue *Q)
{
while(Q->front)
{
Q->rear=Q->front->next;
//这里的Q->rear当一个临时指针使用取出一个头指针指向的结点free一个
free(Q->front);
Q->front=Q->rear;
}
return OK;
}
/* 将Q清为空队列,头指针尾指针还在,都指向头结点 */
Status ClearQueue(LinkQueue *Q)
{
QueuePtr p,q;
Q->rear=Q->front;//先把尾结点提上来指向头结点
p=Q->front->next;//把要删除的头结点的下一个给p
Q->front->next=NULL;//把要头结点指向下一个的指针删除掉
while(p)//一直到最后一个结点都释放掉
{
q=p;
p=p->next;
free(q);
}
return OK;
}
/* 若Q为空队列,则返回TRUE,否则返回FALSE */
Status QueueEmpty(LinkQueue Q)
{
if(Q.front==Q.rear)//指针相等就是空队列 ,也就是都指向头结点,注意头结点不放数据
return TRUE;
else
return FALSE;
}
/* 求队列的长度 */
int QueueLength(LinkQueue Q)
{
int i=0;
QueuePtr p;
p=Q.front;
while(Q.rear!=p)
{
i++;//用于计数
p=p->next;//指针向后
}
return i;
}
/* 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR */
Status GetHead(LinkQueue Q,QElemType *e)
{
QueuePtr p;
if(Q.front==Q.rear)//先判断
return ERROR;
p=Q.front->next;
*e=p->data;
return OK;
}
/* 插入元素e为Q的新的队尾元素 */
Status EnQueue(LinkQueue *Q,QElemType e)
{
QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
if(!s) /* 存储分配失败 */
exit(OVERFLOW);
s->data=e;//先设置要插入的结点的数据域
s->next=NULL;//把这个结点的指针置为空
Q->rear->next=s; /* 把拥有元素e的新结点s赋值给原队尾结点的后继,见图中① */
Q->rear=s; /* 把当前的s设置为队尾结点,rear指向s,见图中② */
return OK;
}
/* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回 ERROR */
Status DeQueue(LinkQueue *Q,QElemType *e)//实际上删除的 队头元素是头结点的下一个!!!
{
QueuePtr p;
if(Q->front==Q->rear)
return ERROR;
p=Q->front->next; /* 将欲删除的队头结点暂存给p,见图中① */
*e=p->data; /* 将欲删除的队头结点的值赋值给e */
Q->front->next=p->next;/* 将原队头结点的后继p->next赋值给头结点后继,见图中② */
//上面的语句相当于指针跳过去了
if(Q->rear==p) /* 若队头就是队尾,则删除后将rear指向头结点,见图中③ */
Q->rear=Q->front;
free(p);
return OK;
}
/* 从队头到队尾依次对队列Q中每个元素输出 */
Status QueueTraverse(LinkQueue Q)
{
QueuePtr p;
p=Q.front->next;
while(p)
{
visit(p->data);
p=p->next;
}
printf("\n");
return OK;
}
int main()
{
int i;
QElemType d;
LinkQueue q;
i=InitQueue(&q);
if(i)
printf("成功地构造了一个空队列!\n");
printf("是否空队列?%d(1:空 0:否) ",QueueEmpty(q));
printf("队列的长度为%d\n",QueueLength(q));
EnQueue(&q,-5);
EnQueue(&q,5);
EnQueue(&q,10);
printf("插入3个元素(-5,5,10)后,队列的长度为%d\n",QueueLength(q));
printf("是否空队列?%d(1:空 0:否) ",QueueEmpty(q));
printf("队列的元素依次为:");
QueueTraverse(q);
i=GetHead(q,&d);
if(i==OK)
printf("队头元素是:%d\n",d);
DeQueue(&q,&d);
printf("删除了队头元素%d\n",d);
i=GetHead(q,&d);
if(i==OK)
printf("新的队头元素是:%d\n",d);
ClearQueue(&q);
printf("清空队列后,q.front=%u q.rear=%u q.front->next=%u\n",q.front,q.rear,q.front->next);
DestroyQueue(&q);
printf("销毁队列后,q.front=%u q.rear=%u\n",q.front, q.rear);
return 0;
}