队列
队列就是一个能够实现“先进先出”的存储结构。队列分为链式队列和静态队列;静态队列一般用数组来实现,但此时的队列必须是循环队列,否则会造成巨大的内存浪费;链式队列是用链表来实现队列
循环队列
牺牲一个元素空间的前提
需要两个指针 :tail (队尾指针)
和head(队头指针)
-
队列初始化时,两个值都为0
-
当队列不为空时,
head
指向队列第一个元素,tail
指向队列最后一个元素的下一个位置,也就下一个元素入队时要放在rear的位置上,而tail
“顺延” -
当tail == head 时, 队列可以为满的,也可以为空的。
满:
(tail +1) %MAXSIZE == head
空:
head==rear
队列的长度:
当tial大于head时: len = tail-head
tail小于head时 : len= tail - head+MAXSIZE
合并起来就是: (tail-head+MAXSIZE )%MAXSIZE
取余的理解
理解:
当tail追上head时,队满。 当head追上tail时, 队空。如果想让一个数约束在 0~n的范围内, 需要将x%n
或者这样理解: 循环队列要解决的问题就是要防止指针越界,所以当tail在数组的 边界值,+1就会越界时,就需要用一个神奇的操作 : mod 。
队列的操作
获取: 对头元素:buff[front]
获取: 队尾元素: buff[tail-1 ]
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct Queue
{
int tail ; //队尾指针
int head ; //队头指针
char* base; //数据数组
int maxsize;
};
typedef struct Queue queue;
queue * initQueue(queue* queue ,int maxsize )
{
if (queue == NULL)
{
queue = (struct Queue*)malloc(sizeof(struct Queue));
}
queue->base = (char*) malloc( sizeof(char) * maxsize );
if (queue->base == NULL)
{
exit(0);
}
queue->head = queue->tail = 0;
queue->maxsize =maxsize ;
return queue;
}
bool isFull(queue* queue)
{
if (queue == NULL) return false ;
return ( (queue->tail + 1) % queue->maxsize == queue->head);
}
void add(queue* queue, char data)
{
// 判断是否队满
if (isFull(queue))
{
printf("队列已满!, 元素 %c 无法入队 \n" ,data ) ;
return ;
}
queue->base[queue->tail] = data;
queue->tail = (queue->tail + 1) % queue->maxsize; //注意这里tail的变化。
}
int count(queue* queue)
{
if (queue == NULL) return 0;
return (queue->tail - queue->head+queue->maxsize ) % queue->maxsize;
}
bool isEmpty(queue* queue)
{
if (queue == NULL) return false;
return (queue->head == queue->tail);
}
char Dequeue(queue* queue)
{
if (isEmpty(queue))
{
printf("队列已空!\n"); return NULL ;
}
char ch = queue->base[queue->head];
queue->head = (queue->head + 1) % queue->maxsize;
return ch;
}
void queueTravel(queue* queue)
{
int head = queue->head, tail = queue->tail;
while (head != tail)
{
printf("%2c",queue->base[head]);
head = ( head + 1) % queue->maxsize;
}
}
int main()
{
queue *Q =NULL ;
char arr[14] = { 'a','b','c','d','e','f','g','h','a','d','s' ,'e','s','e' };
Q= initQueue(Q, 20);
printf("队列初始化成功!\n");
bool a= isEmpty(Q);
if (a) printf("队列为空!\n");
for (int i = 0; i < 10; i++)
{
add(Q, arr[i]);
}
printf("元素已入队\n");
printf("队列中有%d个元素 \n", count(Q));
printf("出队元素: %c\n" , Dequeue(Q)) ;
printf("队列中有%d个元素 \n", count(Q));
for (int i = 10; i < 14; i++)
{
add(Q, arr[i]);
}
queueTravel(Q);
}
题目练习
- 一个顺序存储的循环队列最大能存储的元素数目是100,如果设队头指针(约定为指向队头元素前一位置)和队尾指针的值分别是13和89,那么队列中实际存储元素的个数是____;
若队头指针和队尾指针的值分别是89和13,那么队列中实际存储元素的个数是____。
按照以上公式:
队头小于队尾的时候,将队尾减队头得到 76
队头大于队尾的是偶,有rear-head+maxsize
得到76 , 25。这里有个坑: 就是最大存储元素是100的话,实际上数组的长长度将是101。(要注意题意!)