【定义】
队列和栈有异曲同工之妙,明白栈以后,对理解队列会很快,队列属于先进先出,尾部插入,前面删除,俗称队尾和对头,前删后插。
【顺序存储队列】
【难点解析】
1.假溢出现象
顺序存储结构难点在于出列,出列后数组有位置时的入列情况,引入front指针指向队头元素,rear指针指向队尾元素的下一个位置,空队列时front = rear,出队列时front往后移,入队列时rear往后移,但是会出现一个问题,本身存储队列的是一个数组,后面满了,但是前面还有空位,就导致一种“假溢出”现象,为了解决这个问题,把空间充分利用上,采取循环队列,首尾相接,把rear移动到前面空余空间去添加新成员。
2.满队与空队判断条件
假溢出导致满队和空队一样rear = front, 为了区分空队列和满队列,设置标志变量flag,flag =0 为空,1为满,还有一种办法就是留下一个空余单元,假如数组的最大尺寸为max,则满队条件为(rear+1)%max ==front
3.队列长度
当rear大于front时,长度=rear-front,
当rear小于front时,长度=rear-0+max-front,
通用的计算队列长度公式就是(rear - front +max)%max。
4.结构代码
typedef int my_data;
typedef struct my_queue
{
my_data data[MAX];
int front;
int rear;
}my_queue;
【测试代码】
#include<stdio.h>
#include<stdlib.h>
#define MAX 10
typedef int my_data;
typedef struct my_queue
{
my_data data[MAX];
int front;
int rear;
}my_queue;
//初始化一个空队列
int init_queue(my_queue *Q)
{
Q->front = 0;
Q->rear = 0;
return 0;
}
//入队
int enqueue(my_queue *Q, my_data e)
{
//判断队满?
if((Q->rear+1)%MAX == Q->front)
return 1;
Q->data[Q->rear] = e;
Q->rear = (Q->rear +1)%MAX;//移一位
return 0;
}
//出队
int dequeue(my_queue *Q, my_data *e)
{
//先判断是否为空队
if(Q->rear == Q->front)
return 1;
*e = Q->data[Q->front];
Q->front = (Q->front+1)%MAX;//移一位
return 0;
}
//队列长度
int queue_length(my_queue *Q)
{
return (Q->rear-Q->front+MAX)%MAX;
}
void test(my_queue *Q)
{
int s[MAX];
printf("请输入入队成员\n");
for(int i= 0; i<MAX-1;i++)
{
scanf("%d",&s[i]);
enqueue(Q,s[i]);
}
int length =queue_length(Q);
printf("队列长度%d\n",length);
my_data *e=(my_data *)malloc(sizeof(my_data));
dequeue(Q,e);
printf("谁出去了%d\n",*e);
dequeue(Q,e);
printf("谁出去了%d\n",*e);
}
int main()
{
my_queue *queue = (my_queue *)malloc(sizeof(my_queue));
init_queue(queue);
test(queue);
int length =queue_length(queue);
printf("队列长度%d\n",length);
}
【输出】
这里需要注意的是移动front和rear,怎么向后移一位。
【链队列】
就是一个带头结点的单链表,队头指针指向链队列的头结点,队尾指针指向终端节点,空队列时,front,rear都指向头结点。
【测试代码】
#include<stdio.h>
#include<stdlib.h>
typedef int my_data;
//结点结构
typedef struct QNode
{
my_data data;
struct QNode *next;
}QNode, *Queue_ptr;
//队列的链表结构
typedef struct
{
Queue_ptr front, rear; //队头、队尾指针
}LinkQueue;
int enqueue(LinkQueue *Q, my_data e)
{
Queue_ptr pnew = (Queue_ptr)malloc(sizeof(QNode));
if(!pnew)
{
printf("over flow");
return 1;
}
pnew->data =e;
pnew->next = NULL;
Q->rear->next = pnew;
Q->rear = pnew;
return 0;
}
int dequeue(LinkQueue *Q, my_data *e)
{
//判断是否为空队
if(Q->front == Q->rear)
{
printf("null");
return 1;
}
Queue_ptr p;
p = Q->front->next;//将队头调出来单独操作
*e = p->data;
Q->front->next = p->next;//令队头指向第二个结点
if(Q->rear == p)//如果队头就是队尾,删除了后就没有了,应将rear指向头节点
Q->rear = Q->front;
free(p);
return 0;
}
void test(LinkQueue *Q)
{
int s[3];
printf("input:\n");
for(int i = 0 ;i<3;i++)
{
scanf("%d",&s[i]);
enqueue(Q,s[i]);
}
my_data *e = (my_data*)malloc(sizeof(my_data));
dequeue(Q, e);
printf("谁出来了%d\n",*e);
}
int main()
{
LinkQueue *Q=(LinkQueue *)malloc(sizeof(LinkQueue));
Queue_ptr first =(Queue_ptr)malloc(sizeof(QNode));
first->next = NULL;
Q->front= Q->rear = first;
test(Q);
}
【输出】
这里还是要注意一下头结点和头指针的问题。