队列定义:只允许在一端进行插入,在一端进行删除的线性表。
生活中的很多例子都可以用队列来体现,如买饭排队。
同样类似于栈,队列在电脑中的储存方式也分为两种,顺序储存和链式储存。
顺序储存:
顺序储存结构的情况如下,我们在使用前要确定队列的大小,通过建立数组来储存队列的元素。建立两个指针
来标示队头和队尾,添加元素和删除元素即为移动队头或是队尾。虽然建立方便,但是局限在于无法储存更多的
元素。
进一步的优化,我们产生了循环队列。就是当队尾指针指向了数组中的最后一个元素,即将溢出的时候,我
们就把队尾指向数组的第一个元素,前提是此时的队头指针已经发生了移动。
链式储存:
无论怎样,我们都可以看出顺序储存队列对于长度方面的不足,即使是加入了循环队列仍然无法满足需求。
因此我们加入了队列的链式储存结构。
队列的链式储存结构就是单向链表,但是我们在使用它的时候保持了头出尾加的原则。
为了更加清晰的说明队列的链式储存结构,在这里引入一道程序设计题。
题目:关于排队打饭的问题
首先输入一个整数m(m<10000),代表当前有m个人
第二行输入m个数,代表每个人的编号
第三行输入一个整数n(n<10000),代表队列变动和询问一共n次
以后n行,JOIN X(或 J X)表示编号为X(保证与以前的编号不同)的人加入;
ASK Z(或 A Z)(Z小于当前队列长度)表示询问第Z个位置上的人的编号;
FINISH D(或 F D)表示有D个人买完饭离开了;
LENGTH(或 L)表示询问队列的长度 。保证所有数据在int 范围内。同时打印队列。
使用链式储存结构编写程序,如下:
#include<stdio.h>
#include<stdlib.h>
/*建立每个节点的格式*/
struct Node
{
int data;
struct Node *next;
};
/*有两个指针节点构成的队列*/
struct queue
{
struct Node *front;
struct Node *rear;
};
/*初始化一个队列*/
void initqueue(struct queue *hp)
{
hp->front=hp->rear=NULL;
}
/*向队列中储存一个新的数据x*/
void inqueue(struct queue *hp,int x)
{
struct Node *newNode;/*建立一个指针节点指向刚刚建立的节点*/
newNode=malloc(sizeof(struct Node));
if(newNode==NULL)
{
printf("内存分配失败!");
exit(1);
}
newNode->data=x;/*将x的值赋给节点的值域*/
newNode->next=NULL;/*新加入的节点在最后,因此所指向为空*/
/*队列为空,则即为队首节点也为队尾节点*/
if(hp->rear==NULL)
{
hp->front=hp->rear=newNode;
}
/*若队列并非为空,则修改队尾节点的指针域和队尾指针,使之指向新的队尾节点*/
else
{
hp->rear=hp->rear->next=newNode;
}
}
/*从队列中删除一个元素*/
int delqueue(struct queue *hp)
{
struct Node *p;
int temp;
/*若队列为空则停止运行*/
if(hp->front==NULL)
{
printf("队列为空,无法删除元素!");
exit(1);
}
temp=hp->front->data;
p=hp->front;
hp->front=p->next;
if(hp->front==NULL)
{
hp->rear=NULL;
}
free(p);
return temp;
}
/*读取队首元素*/
int peekqueue(struct queue *hp)
{
/*若链队为空则停止运行*/
if(hp->front==NULL)
{
printf("队列为空,无法删除!");
exit(1);
}
return hp->front->data; /*返回队首元素*/
}
/*检查链队是否为空,若为空则返回i1,否则返回0*/
int emptyqueue(struct queue *hp)
{
/*判断队首或队尾任一个指针是否为空即可*/
if(hp->front==NULL)
{
return 1;
}
else
{
return 0;
}
}
/*清除链队中的所有元素*/
void clearqueue(struct queue *hp)
{
struct Node *p=hp->front;/*队首指针赋给p*/
/*依次删除队列的每一个结点,最后使队首指针为空*/
while(p!=NULL)
{
hp->front=hp->front->next;
free(p);
p=hp->front;
}
/*循环结束后队首指针已经为空*/
hp->rear=NULL;/*使队尾指针为空*/
}
/*遍历队列中的元素*/
void lookqueue(struct queue *hp)
{
int i=0;
struct Node *q=hp->front,*p=hp->front;/*队首指针赋给p*/
while(p!=NULL)
{
printf("%2d",q->data);
p=p->next;
q=p;
i++;
}
printf("\n");
printf("队列长度为%d\n",i);
}
/*查找某个位置所存放的元素*/
void findqueue(struct queue *hp,int x)
{
int i=1;
struct Node *q=hp->front,*p=hp->front;/*队首指针赋给p*/
while(p!=NULL)
{
if(i==x)
{
printf("%d\n",q->data);
}
p=p->next;
q=p;
i++;
}
}
void main()
{
int n, m, i, num[10000] ;
int x, y, z, d ;
int p = 1, c = 0 ;
char str[50];
struct queue q;
initqueue(&q);
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&x);
inqueue(&q,x);
}
scanf("%d", &n) ;/*进行操作的次数*/
c = m;
while(n--)
{
scanf("%s", str) ;
if(strcmp(str,"JOIN") == 0||strcmp(str,"J")==0)/*添加新的元素*/
{
scanf("%d", &x) ;
inqueue(&q,x);
}
if(strcmp(str, "ASK") == 0||strcmp(str,"A")==0)/*通过位置查找存放元素*/
{
scanf("%d", &z) ;
findqueue(&q,z);
}
if(strcmp(str, "LENGTH") == 0||strcmp(str,"L")==0)/*显示当前队列的长度*/
{
lookqueue(&q);
}
if(strcmp(str, "FINISH") == 0||strcmp(str,"F")==0)/*删除队列中的元素*/
{
scanf("%d", &d) ;
for(i=1;i<=d;i++)
delqueue(&q);
}
}
}
这道题如果使用顺序储存结构会更加的简单,代码也会更加的短小,但是仍建议使用链式储存结构养成好习惯。
顺序储存结构:
#include<stdio.h>
#include<string.h>
void main()
{
int n, m, i, num[10000] ;
int x, y, z, d ;
int p = 1, c = 0 ;
char str[100] ;
scanf("%d", &m);/*初始有几个结点*/
for(i = 1 ; i <= m; i++)
scanf("%d", &num[i]) ;/*每个结点所存放的数据*/
scanf("%d", &n) ;/*进行操作的次数*/
c = m;
while(n--)
{
scanf("%s", str) ;
if(strcmp(str,"JOIN") == 0||strcmp(str,"J")==0)/*添加新的元素*/
{
scanf("%d", &x) ;
num[++c] = x ;
}
if(strcmp(str, "ASK") == 0||strcmp(str,"A")==0)/*通过位置查找存放元素*/
{
scanf("%d", &z) ;
printf("%d\n", num[p+z-1]) ;
}
if(strcmp(str, "LENGTH") == 0||strcmp(str,"L")==0)/*显示当前队列的长度*/
{
printf("%d\n", c-p+1) ;
}
if(strcmp(str, "FINISH") == 0||strcmp(str,"F")==0)/*删除队列中的元素*/
{
scanf("%d", &d) ;
p = p + d ;
}
}
}