队列,是一种操作被限制的线性表,分为顺序队列(循环)和链式队列
一、循环顺序队列
1、基本概念
存储就是数组,一个队列头指针(数组的下标),一个队列尾指针(数组的下标),入队只能从数组尾入(下标大的),出队只能从数组头出(下标小的),可以循环存放。
队列遵循先入先出,后入后出的规则
2、名词解释
MAXSIZE:数组的最大存放值
front:头指针
rear:尾指针
3、队列的判定与计算通式
1、队空:front=rear
2、队满:front==(rear+1)%MAXSIZE
3、队长度:(rear-front+MAXSIZE)%MAXSIZE
实则是两部分组成:1.当rear<front时 ((MAXSIZE-front)+rear)%MAXSIZE
2.当rear>front (rear-front)% MAXSIZE
4、循环移动:rear=(rear+1)%MAXSIZE
front=(front+1)%MAXSIZE
4、头尾指针的位置
因为队空判断和队满判断的原因,所以一般规定头指针front指向的数组元无数据,尾指针rear指向的数组元有数据,初始化时使得头尾指针都为-1.
5、循环队列的操作
(1)队列结构的定义
typedef struct stu//队列的结构定义
{
int a[MAXSIZE];//队列存储的空间
int front,rear;//数组的下标,循环队列的头尾指针
}squ;
(2)队列结构的初始化
squ* Initqueue()//队列结构初始化
{
squ* st=(squ*)malloc(sizeof(squ));
st->front=-1;//头尾都为0,此时是空对
st->rear=-1;//
return st;
}
(3)入队
void pushSqueue(squ* st1,int n)//入队,在尾,n是入队的数据
{
if(st1->front==(((st1->rear)+1)%MAXSIZE))
{
printf("!!!!入队失败\n");
return;//判断满队不能入队
}
st1->rear=(st1->rear+1)%MAXSIZE;//移动尾指针
st1->a[st1->rear]=n;//将数据放入尾指针的地址
}
(4)出队
int popSqueue(squ* st)//出队,在头,返回的是出队的数据
{
int n;
if(st->front==st->rear)return 0;//判断是否队空
st->front=(st->front+1)%MAXSIZE;//移动头指针
n=st->a[st->front];//将头指针的数据出给n
return n;
}
(5)清队
void claerqueue(squ* st)//清除队列
{
if(st->front==st->rear)return;//判断队列是否为空
st->front=-1;//不为空置为空队列
st->rear=-1;//
return;
}
(6)展示队
void showqueue(squ* st)//展示队列内容
{
int i=0;//头尾指针都不能随意移动,所以用个i代替移动
printf("队列的展示:\n");
for(i=((st->front)+1);i<=(st->rear);i=(i+1)%MAXSIZE)//
{
printf("%d ",st->a[i]);
}
putchar('\n');
printf("队列的长度为:%d\n",((st->rear)-(st->front)+MAXSIZE)%MAXSIZE);
}
6、总程序
//队空:front=rear
//队满:front==(rear+1)%MAXSIZE
//队长度:(rear-front+MAXSIZE)%MAXSIZE
//循环移动:rear=(rear+1)%MAXSIZE
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
typedef struct stu//队列的结构定义
{
int a[MAXSIZE];//队列存储的空间
int front,rear;//数组的下标,循环队列的头尾指针
}squ;
squ* Initqueue()//队列结构初始化
{
squ* st=(squ*)malloc(sizeof(squ));
st->front=-1;//头尾都为0,此时是空对
st->rear=-1;//
return st;
}
void pushSqueue(squ* st1,int n)//入队,在尾,n是入队的数据
{
if(st1->front==(((st1->rear)+1)%MAXSIZE))
{
printf("!!!!入队失败\n");
return;//判断满队不能入队
}
st1->rear=(st1->rear+1)%MAXSIZE;//移动尾指针
st1->a[st1->rear]=n;//将数据放入尾指针的地址
}
int popSqueue(squ* st)//出队,在头,返回的是出队的数据
{
int n;
if(st->front==st->rear)return 0;//判断是否队空
st->front=(st->front+1)%MAXSIZE;//移动头指针
n=st->a[st->front];//将头指针的数据出给n
return n;
}
void claerqueue(squ* st)//清除队列
{
if(st->front==st->rear)return;//判断队列是否为空
st->front=-1;//不为空置为空队列
st->rear=-1;//
return;
}
void showqueue(squ* st)//展示队列内容
{
int i=0;//头尾指针都不能随意移动,所以用个i代替移动
printf("队列的展示:\n");
for(i=((st->front)+1);i<=(st->rear);i=(i+1)%MAXSIZE)//
{
printf("%d ",st->a[i]);
}
putchar('\n');
printf("队列的长度为:%d\n",((st->rear)-(st->front)+MAXSIZE)%MAXSIZE);
}
void main()
{
squ* st;
int n;
st=Initqueue();//队列结构初始化
pushSqueue(st,10);//入队,在尾,n是入队的数据
pushSqueue(st,20);
pushSqueue(st,30);
pushSqueue(st,40);
n=popSqueue(st);//出队,在头,返回的是出队的数据
printf("出队的数据为:%d\n",n);
//claerqueue(st);//清除队列
showqueue(st);//展示队列内容
}
二、队链
实则就是链表的操作限制,从头出队,尾插法入队,所以用到两个指针,一个指向头head,一个指向尾rear
1、节点结构和队结构
typedef struct lnode//节点结构
{
int data;//节点的数据域
struct lnode* next;//节点的指针域
}Listnode;
typedef struct//队结构
{
int num;//计数
Listnode *head,*rear;//头尾指针
}prequeue;
2、队的初始化
prequeue* Init()//维护的初始化,返回维护结构的地址
{
prequeue* st=(prequeue*)malloc(sizeof(prequeue));//申请队结构的内存空间
st->num=0;//初始化将队列的计数为0
st->head=st->rear=NULL;//头尾指针指向NULL
return st;//返回队结构的地址
}
3、入队(链队没有内存的限制)
void pushqueue(prequeue* st,int n)//入队(队结构的地址,入队的数据)
{
Listnode* tmp;//新节点的地址
if(!st)return;
tmp=(Listnode*)malloc(sizeof(Listnode));//申请新新节点的空间
tmp->data=n;//节点的初始化
tmp->next=NULL;
if((st->num)==0)//如果是第一次入队列
{
st->rear=st->head=tmp;//头指针指向新节点
(st->num)++;
return;
}
else
{
st->rear->next=tmp;//将尾节点的指针域指向新节点tmp
st->rear=st->rear->next;//移动尾指针指向新入队的节点
(st->num)++;
return;
}
}
4、出队
int popqueue(prequeue* st)//出队,返回出队的数据
{
int n;
Listnode *p=NULL;
if(!st || !(st->num))return 0;
p=st->head;//从队头出
n=p->data;
st->head=st->head->next;//移动头指针到下一个节点
free(p);
p=NULL;
(st->num)--;
return n;//
}
5、队遍历
void readqueue(prequeue* st)//遍历输出队列
{
Listnode* p;
if(!st || !(st->num))return;
p=st->head;//从队头开始
while(p!=NULL)//p不指向空
{
printf("%d ",p->data);
p=p->next;//移动p
}
putchar('\n');
}
6、清除队
void clearqueue(prequeue *st)//清空队列
{
Listnode *p;
if(!st || st->num==0)return;
while(!(st->head==NULL))//头指针不为NULL时代表队列不为空
{
p=st->head;//从头开始
st->head=st->head->next;//头指针移动到下一个节点
free(p);//释放上一个节点
p=NULL;
(st->num)--;
}
}
7、总程序
#include <stdio.h>
#include <stdlib.h>
typedef struct lnode//节点结构
{
int data;//节点的数据域
struct lnode* next;//节点的指针域
}Listnode;
typedef struct//队结构
{
int num;//计数
Listnode *head,*rear;//头尾指针
}prequeue;
prequeue* Init()//维护的初始化,返回维护结构的地址
{
prequeue* st=(prequeue*)malloc(sizeof(prequeue));//申请队结构的内存空间
st->num=0;//初始化将队列的计数为0
st->head=st->rear=NULL;//头尾指针指向NULL
return st;//返回队结构的地址
}
void pushqueue(prequeue* st,int n)//入队(队结构的地址,入队的数据)
{
Listnode* tmp;//新节点的地址
if(!st)return;
tmp=(Listnode*)malloc(sizeof(Listnode));//申请新新节点的空间
tmp->data=n;//节点的初始化
tmp->next=NULL;
if((st->num)==0)//如果是第一次入队列
{
st->rear=st->head=tmp;//头指针指向新节点
(st->num)++;
return;
}
else
{
st->rear->next=tmp;//将尾节点的指针域指向新节点tmp
st->rear=st->rear->next;//移动尾指针指向新入队的节点
(st->num)++;
return;
}
}
int popqueue(prequeue* st)//出队,返回出队的数据
{
int n;
Listnode *p=NULL;
if(!st || !(st->num))return 0;
p=st->head;//从队头出
n=p->data;
st->head=st->head->next;//移动头指针到下一个节点
free(p);
p=NULL;
(st->num)--;
return n;//
}
void readqueue(prequeue* st)//遍历输出队列
{
Listnode* p;
if(!st || !(st->num))return;
p=st->head;//从队头开始
while(p!=NULL)//p不指向空
{
printf("%d ",p->data);
p=p->next;//移动p
}
putchar('\n');
}
void clearqueue(prequeue *st)//清空队列
{
Listnode *p;
if(!st || st->num==0)return;
while(!(st->head==NULL))//头指针不为NULL时代表队列不为空
{
p=st->head;//从头开始
st->head=st->head->next;//头指针移动到下一个节点
free(p);//释放上一个节点
p=NULL;
(st->num)--;
}
}
void main()
{
//int ndata;//
prequeue *st;//定义队结构
st=Init();//初始化
pushqueue(st,10);//入队
pushqueue(st,20);
pushqueue(st,30);
pushqueue(st,40);
pushqueue(st,50);
//ndata=popqueue(st);//出队
readqueue(st);//遍历队
//printf("出队的数据%d ,队长度为%d \n",ndata,st->num);
clearqueue(st);//清除队
printf("执行清除后的剩余的队列长度为%d\n",st->num);
}