一、队列的概念
1、队列的定义
队列:数据结构线性表的一种,它与栈不同,栈是先进后出,而队列是先进先出,在队尾入列,在队头出列。
队头(head):队列中出队列的一端
队尾(tail):队列中插入队列的一端
二、队列的顺序储存结构
1.顺序存储的理解
在内存上开辟一段连续的内存空间
将低地址空间作为队头,向高地址存放数据
因此我们定义一个队列结构
#define Queue_Max 6
typedef int QueueType;
typedef struct QueueNode
{
QueueType list[Queue_Max];//队列数组,容量为5
int first;//首元素前一个位置下标
int rear;//尾元素下标位置
}Queue;
当队列为空时,此时队列没有元素,令first=rear=-1,当存放一个数据x时,令rear+=1,list[rear]=x,此时rear指向的是尾元素下标,first不变,以此类推,当存放6个数据后,rear变为了5,此时队列满了,以及无法再插入数据。
当队列满时,我们进行出队列,当出一个元素时,令first+=1,然后取出该下标的数据,以此类推,当出队列至最后一个数据时,first=4,出完后,first=rear=5,此时队列为空,且无法再存储数据。
综上,我们可知
1.队列为空的条件是first==rear
2.队列为满的条件是rear=Queue_Max-1
3.进队列时,先将rear下标+1,再插入数据至list数组的rear位置
4.出队列时,先将first下标+1,再取出list数组的first位置的数据
2.顺序存储的算法实现
2.1初始化队列
//初始化
void QueueInit(Queue* que)
{
assert(que);//断言是否为空
que=(Queue*)malloc(sizeof(Queue));
que->first=que->rear=-1;//
}
2.2销毁队列
void QueueDestroy(Queue* que)
{
free(que);
}
2.3进队列
void QueuePush(Queue* que, QueueType x)
{
assert(que);
if(!QueueFull(que)//检查队列是否满了
{
rear+=1;
que->list[rear]=x;
}
}
2.4出队列
void QueuePop(Queue* que,QueueType* e)
{
assert(que);
if(!QueueEmpaty(que)//判断队列是否为空
{
first+=1;
*e=que->list[first];
}
}
2.5判断队列是否为满
bool QueueFull(Queue* que)
{
assert(que);
return que->rear==Queue_Max-1;
}
2.6判断队列是否为空
bool QueueEmpaty(Queue* que)
{
assert(que);
return que->first==que->rear;
}
2.7取队尾元素
QueueType QueueBack(Queue* que)
{
assert(que);
assert(!QueueEmpty(que));
return que->list[rear];
}
3、循环队列
在顺序储存结构基础上实现循环队列,就是可以实现出队列的空间也可以插入数据,形成循环。
比如当队列为空且rear=Queue_Max-1时,如果是循环队列,那么rear会变成0,然后在list数组的rear位置插入数据
当我们再插入5个数据时,此时rear=first且队满,但是和判断队空的条件重复了,那么怎么办才能将两种情况区分开呢?
如果我们让rear和first初始化为0,使first指向的数组下标位置始终为空(数组不能free,实际含有数据,所以我们只需将list数组的first位置看作是无效数据),当插入4个数据后此时队满,满足rear=(first-1+Queue_Max)%Queue_Max,这样就能把空和满区分开来。
因此我们需要将原来的代码改进
//改进后
//初始化
void QueueInit(Queue* que)
{
que=(Queue*)malloc(sizeof(Queue));
que->first=que->rear=0;
}
//判断队满
bool QueueFull(Queue* que)
{
assert(que);
return rear==(first-1+Queue_Max)%Queue_Max;
}
//进队
void QueuePush(Queue* que,QueueType x)
{
assert(que);
assert(!QueueFull(que));
rear=(rear+1)%Queue_Max;
que->list[rear]=x;
}
//出队
void QueuePop(Queue* que,QueueType* e)
{
assert(que);
assert(!QueueEmpaty(que));
first=(first+1)%Queue_Max;
*e=que->list[first];
}
三、队列的链式储存结构
1、链式储存的理解
队列的数据之前的逻辑关系是线性结构,因此可以用链式的形式来储存,这种链式储存的形式叫做链队。这里我们使用单链表的形式,所以只能在链表的表头进行删除操作(出队),在链表的表尾进行插入操作(进队),因此我们需要记录链表的头结点(head)和尾结点(tail),和链栈一样,链队也不存在队满上溢出的情况。
2、队列链式结构的常见操作
//初始化
void QueueInit(Que* que);
//销毁
void QueueDestroy(Que* que);
//插入
void QueuePush(Que* que, QueDateType x);
//删
void QueuePop(Que* que);
//判断空
bool QueueEmpty(Que* que);
//打印
void QueuePrint(Que* que);
//创建队列元素
Queue* QueueBuy(QueDateType x);
//取队列首元素
QueDateType QueueFront(Que* que);
//取队列尾元素
QueDateType QueueBack(Que* que);
3、算法实现
//初始化
void QueueInit(Que* que)
{
assert(que);
que->head = que->tail = NULL;
}
//创建队列元素
Queue* QueueBuy(QueDateType x)
{
Queue* newnode = (Queue*)malloc(sizeof(Queue));
newnode->data = x;
newnode->next = NULL;
return newnode;
}
//销毁
void QueueDestroy(Que* que)
{
assert(que);
if (que->head == que->tail)
{
free(que->head);
que->head = que->tail = NULL;
}
else
{
Queue* cur = que->head;
while (cur)
{
Queue* next = cur->next;
free(cur);
cur = next;
}
}
}
//插入
void QueuePush(Que* que, QueDateType x)
{
assert(que);
Queue* newnode = QueueBuy(x);
if (que->head == NULL)
{
que->head = newnode;
que->tail = newnode;
}
else
{
que->tail->next = newnode;
que->tail = newnode;
}
}
//删
void QueuePop(Que* que)
{
assert(que);
assert(que->head);
if (que->head == que->tail)
{
free(que->head);
que->head = que->tail = NULL;
}
else
{
Queue* next = que->head->next;
free(que->head);
que->head = next;
}
}
//判断空
bool QueueEmpty(Que* que)
{
assert(que);
return que->head == NULL;
}
//打印
void QueuePrint(Que* que)
{
assert(que);
printf("pop<- ");
Queue* cur = que->head;
while (cur)
{
Queue* next = cur->next;
printf("%d ", cur->data);
cur = next;
}
printf(" <-push\n\n");
}
//取队列首元素
QueDateType QueueFront(Que* que)
{
assert(que);
assert(!QueueEmpty(que));
return que->head->data;
}
//取队列尾元素
QueDateType QueueBack(Que* que)
{
assert(que);
assert(!QueueEmpty(que));
return que->tail->data;
}