目录
一、队列基础知多少
在数据结构的大家庭中,队列是一种非常重要且基础的数据结构,它遵循着先进先出(First In First Out,FIFO)的原则。就像我们日常生活中排队买票一样,先排在队伍中的人会先买到票并离开队伍,后来的人则依次在队尾加入排队 。在队列中,允许插入元素的一端称为队尾(rear),允许删除元素的一端称为队头(front)。当队列中没有任何元素时,我们称其为空队列。
比如,你去银行办理业务,取号之后,会按照号码从小到大的顺序依次等待叫号办理,先取号的人先办理,这就是典型的队列应用场景。在计算机领域,队列也有着广泛的应用,像操作系统中的进程调度、广度优先搜索算法(BFS)等,都离不开队列的支持。 队列常见的基本操作有:初始化队列(InitQueue),用于创建一个空队列;判断队列是否为空(QueueEmpty);入队操作(EnQueue),将元素添加到队尾;出队操作(Dequeue),从队头删除元素;获取队头元素(GetHead),返回队头元素的值但不删除它 。这些操作构成了队列的基本功能,是我们后续深入学习循环队列和链队列的基础。
二、循环队列:环环相扣的存储魔法
(一)结构与原理大揭秘
循环队列是一种特殊的队列,它在逻辑上是一个环形的结构 。从结构定义来看,它通常使用数组来存储元素,同时设有两个指针,一个是头指针front,用于指向队列的头部元素;另一个是尾指针rear,指向队列尾部元素的下一个位置。
它的循环原理是通过取模运算(%)来实现的。当rear指针移动到数组末尾时,如果数组头部还有空闲空间,下一个入队的元素就可以重新从数组头部开始存储。比如,假设数组大小为n,当rear到达n - 1位置后,下一次入队时rear会通过(rear + 1) % n计算,重新回到位置0,就好像队列的首尾相连形成了一个环 。这样做的好处是避免了普通顺序队列在队头元素出队后,队头前面的空间无法被利用的问题,大大提高了空间利用率 。举个例子,假如我们有一个大小为 5 的循环队列数组[0, 0, 0, 0, 0],初始时front = 0,rear = 0。当元素1入队时,rear变为(0 + 1) % 5 = 1,元素1存放在位置1;当元素2入队时,rear变为(1 + 1) % 5 = 2,元素2存放在位置2;当元素3、4、5依次入队后,rear分别变为3、4、0 。
(二)操作实现全解析
初始化:
在初始化循环队列时,我们需要将头指针front和尾指针rear都设置为0,表示队列为空。以 C 语言代码为例:
#define MAXSIZE 100
typedef struct {
int data[MAXSIZE];
int front;
int rear;
} CirQueue;
void InitQueue(CirQueue *Q) {
Q->front = Q->rear = 0;
}
入队:
入队操作是将新元素添加到队列尾部。首先要判断队列是否已满,如果已满则无法入队;否则,将新元素存入rear指针指向的位置,然后rear指针后移(通过取模运算实现循环移动)。代码如下:
int EnQueue(CirQueue *Q, int x) {
if ((Q->rear + 1) % MAXSIZE == Q->front) {
// 队列已满
return 0;
}
Q->data[Q->rear] = x;
Q->rear = (Q->rear + 1) % MAXSIZE;
return 1;
}
出队:
出队操作是从队列头部删除元素。先判断队列是否为空,若为空则无法出队;否则,取出front指针指向的元素,然后front指针后移(同样通过取模运算实现循环移动)。代码如下:
int DeQueue(CirQueue *Q, int *x) {
if (Q->front == Q->r