简介
队列和栈一样,是线性表的一个特例,队列限定再一端进行插入操作,在另一端进行删除操作,插入端称为队尾,删除段称为队头,队列有先进先出的特点,而栈有后进先出的特点。
与栈类似,队列的常见操作有:创建空队列,判空,入队,出队,取队头元素等等,下面逐一进行讲解。
队列分为链队列和循环队列两类,先介绍链队列
链队列
链队列即为采用链式存储的队列,队头指针指向链队列的第一个结点,队尾指针指向最后一个结点
链队列类型定义
类型定义:链队列首先就要有链式存储的结点结构,即结点的数据域和指针域,其次就是队列的结构,即队头类型和队尾类型(都为结点)
typedef int DataType;
sturct Node
{
DataType data;
struct Node *link;
};
typedef struct Node*PNode;//链式结点类型
struct Queue
{
PNode f;//队头
PNode r;//队尾
};
typedef struct Queue * LinkQueue;//链队列类型
创建链式空队列
空队列创建:首先要申请Queue结构体空间,然后队头、队尾指针为空,返回指向该结点的指针。
//空队列创建
LinkQueue SetNullQueue_Link()
{
LinkQueue lqueue=(LinkQueue)malloc(sizeof(struct Queue));
if(lqueue==NULL)
printf("FF Alloc faliure!");
else
{
lqueue->f=NULL;
lqueue->r=NULL;
}
return lqueue;
}
链队列判空
队列判空:检查队头指针是否为空即可,空返回1,否则返回0
int IsNullQueue_Link(LinkQueue lqueue)
{
return (lqueue->f==NULL)
}
链队列入队
队列入队:首先要申请结点空间,若申请成功,则为结点的数据域和指针域赋值,若队列为空,队头和队尾都指向入队的第一个结点,否则在队尾插入即可。
void EnQueue_Link(LinkQueue lqueue,DataType x)
{
PNode p=(PNode)malloc(sizeof(struct Node));
if(p==NULL)
printf("FF Alloc faliure!");
else
{
p->data=x;
p->link=NULL;
if(lqueue->f==NULL)
{
lqueue->f=p;
lqueue->r=p;
}
else
{
lqueue->r->link=p;//结点插入队尾,即改变最后一个结点的指针域
lqueue->r=p;//修改队列尾指针,即改变队列的尾结点
}
}
}
栈队列出队
队列出队:检查队列是否为空,若不为空,修改队头指针,释放队头结点
void DeQueue_Link(LinkQueue lqueue)
{
PNode p;
if(lqueue->f==NULL)
{
printf("It is enpty queue!");
}
else
{
p=lqueue->f;//p指向队头结点,方便释放
lqueue->f=lqueue->f->link;//修改队头指针
free(p);//释放结点空间
}
}
取链队列队头元素
取队头:首先判断队列是否为空,不为空返回队头
DataType FrontQueue_Link(LinkQueue lqueue)
{
if(lqueue->f==NULL)
{
printf("It is empty queue!");
return 0;
}
else
{
return (lqueue->f->data);//返回队头结点数据域
}
}
循环队列
循环队列简介:队列采用顺序存储时会出现假溢出的现象,即当队列有元素出队时,元素原来的位置不能成功用于后续入队的元素,使用循环队列能很好解决假溢出的问题,假设队头指针 f 和队尾指针 r 重合,形成闭环的循环队列。
循环队列类型定义
循环队列类型定义:循环队列是基于顺序存储的方式实现的,所以不需要链式存储的结点定义,但是需要明确队列的空间最大值,队头、队尾指针以及队列的元素空间。
typedef int DataType;
struct Queue
{
int Max;//队列空间最大值
int f;//队头指针
int r;//队尾指针
DataType *elem;
};
typedef struct Queue*SeqQueue;
创建循环空队列
循环空队列创建:创建队列先要申请结构体空间,然后再申请一个数组空间,再将队头和队尾设置为零;
SeqQueue SetNullQueue_Seq(int m)
{
SeqQueue squeue=(SeqQueue)malloc(sizeof(struct Queue));
if(squeue==NULL)
{
printf("FF Alloc faliure!");
return 0;
}
else
{
squeue->elem=(int *)malloc(sizeof(DataType)*m);
if(squeue->elem!=NULL)
{
squeue->Max=m;//设置循环队列最大值空间
squeue->f=0;//队头初值
squeue->r=0;//队尾初值
return squeue;
}
}
}
循环队列判空
循环队列判空:检查队头指针和队尾指针是否相等,相等则队列为空,返回1,否则返回0
int IsNullQueue_seq(SeqQueue squeue)
{
return (squeue->f==squeue->r);
}
循环队列入队
循环队列入队:先检查队列是否已经满了,若不满,则将元素插入队尾,再修改尾指针
void EnQUeue_Seq(SeqQueue squeue,DataType x)
{
if((squeue->r+1)%(squeue->Max)==squeue->f)
printf("It is FULL Queue");
else
{
squeue->elem[squeue->r]=x;//元素插入队尾
squeue->r=(squeue->r+1)%(squeue->Max);//尾指针+1
}
}
循环队列出队
循环队列出队:首先要判断队列是否为空,不为空则删除队头元素,修改队头指针
void DeQueue_seq(SeqQueue squeue)
{
if(IsNullQueue_seq(squeue))
printf("It is empty queue");
else
squeue->f=(squeue->f+1)%(squeue->Max);//队头指针+1
}
循环队列取队头元素
循环队列取队头元素:先检查队列是否为空,不为空返回队头元素
DataType SeqQueue(SeqQueue squeue)
{
if(squeue->f==squeue->r)
printf("It is empty squue!");
//if(IsNullQueue_seq(squeue))
//printf("It is empty squue!");
else
return (squeue->elem[squeue->f]);
}
总结
队列和栈一样,都是在解决数据结构的问题中常用到的,类似的也能用于迷宫问题广度解决中、农夫过河、二叉树的遍历等常见问题中,灵活的运用能够很好的解决问题。
可以参考以下内容进行队列运用的理解:
PTA上循环队列的入队和出队
二叉树的非递归建立和层次遍历
创作不易,感谢支持(ಥ _ ಥ)