队列,顾名思义就是排队呗。那就是先到先得,谁先进去谁就先出来。
队列就是只允许在一端进行插入,另一端进行删除的线性表。
一、 定义
顺序存储的队列代码
typedef struct{
int data[MAXSIZE];
int font=0;//指前面的指针
int rear=0;//指队尾的指针
}Qq,*pQq;
线性表有顺序储存和链式储存两种方式,队列是线性表所以也有顺序储存和链式储存两种方式。
二、假溢出与循环队列、队列的空与满
队列为空时:队列为空时,队头与队尾都在一起,均指向数组下标为零的位置 ⬇
回忆一下栈空与栈满的判断:通常规定,栈顶指针top = -1 时,判定栈为空;top = MAXSIZE - 1时栈满。(没指进去就是空,指到最后一个就是满)
那两个怎么记才不会弄混呢:
栈是只有一边能入栈、出栈,只需要一个指针就够了,走到哪指到哪所以指到MASXSIZE-1的时候就是满。
队列一边入队,一边出队,所以需要两个指针,那么只要两个指针之间有间隔就说明有东西,所以队为空时,两个指针指在一起。走到哪就指到他后面。所以为空时的时候你可以认为是他本来也想像栈一样指外面但是又因为是走到哪就指到他后面,所以就进去了,并且指向了下标为0的地方。
那么随着不断增加数据,rear后移,队列满 ⬇
队列中的数据不断出队,队头指针不断后移 ⬇
rear指针就会移动到数组之外?不确定,再看一眼?😮😮😮那怎么办,有五个位置,但是只存了三个数据rear就指到外面去了,那里面不能再继续存数了吗?
或者就算front指针不后移,只有rear后移,那他指出数组之外就能说是发生了错误吗?
这就叫假溢出,就像你去上课,到了教室发现所有人都是从第三排开始坐的,所有第三排以后的作为都坐满了,但是你不能说叫教室满了没地方坐了你不上课了。
解决假溢出的方法就是循环队列,即头尾相接,围城一个圈。
但是,新的问题又出现了,围成一个圈之后,队头和队尾指针又指在了一起,这你怎么区分到底是满还是空?
所以,队列为满的条件就是
满:(rear+1)%QueueSize == front
怎么记呢,看下面这张图,看完就记住了,rear+1取余数组长度就=队头的位置
空:Q->rear == Q->front
三、循环队列求队列长度与入队出队
1. 循环队列求队列长度
int QueueLength(pSQ Q){
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
2.入队
void EnQueue(pSQ Q,int e){
if(Q->rear+1)%MAXSIZE == Q->front)//判断是否队满
return;
else{
Q->data[Q->rear] = e;//队尾的位置有数据了
Q->rear = (Q->rear+1)%MAXSIZE;//队尾往后移,但是还要小心他又加回了下标为0的地方所以
//还要取余MAXSIZE
return;
}
}
3.出队
void DeQueue(pSq Q){
//先判断队列是否为空
if(Q->rear == Q-> front) return;
else {
Q->front = (Q->front+1)%MAXSIZE;
//不为空 队头指针后移
return;
}
}
四、链队列
1. 结构
//结点
typedef struct QNode{
int data;
int *next;
}QN,pQN;
//队列
typedef struct{
pQN front;//之前是int ,为什么现在是pQN?
//因为之前front存的是数组下标,但现在存的是每个结构体的地址
//也就是结构体指针
pQN rear;
}LQ;
2. 入队
pQN EnQueue(pQN head,int e){
pQN Q = (pQN)malloc(sizeof(QN));
Q->data = e;
Q->next = NULL;
head -> rear ->next = Q;
head -> rear = Q;
return head;
}
3.出队
pQN DeQueue(pQN Q){
if(head -> front == head -> rear) return 0;
pQN p;
//先用一个指针把原来队头的next存下来
p = Q -> front -> next;
//原来队头的next是新的队头
Q -> front = p;
//新的队头的next是原来队头next的next,也就是p的next
Q -> front -> next = p -> next;
if(Q->rear == p) Q->rear = Q->front;//如果队头是队尾,rear指向头结点
free(p);
return Q;
}