系列文章目录
前言
队列这个数据结构大家都很熟悉了,本质其实就是一个入数据只能在尾入,出数据只能在头出的顺序表。
一、顺序队列的缺点
进行入队操作时,和顺序表一样,直接在队列尾部插入数据,时间复杂度为O(1)。
但是在出队时,为了维护队头,所有的元素都得向前移动,此时时间复杂度为O(N)。
元素的移动非常耗费性能,我们能不能取消元素存储在数组的前面这个限制呢,这样在进行出队操作的时候,就不用再进行元素的移动了。
二、循环队列
1.循环队列的定义
typedef struct CircularQueue
{
DataType* arr;
int head;
int tail;
int N;
}CQueue;
队列大小为N,由于循环队列需要一个辅助空间,来区分循环队列为满还是为空两个情况,所以在开辟空间的时候,需要多开辟一个元素的空间。
循环队列唯一的难点就是如何判断队列为空和队列为满两个情况。
1.队列为空
假设队列大小为4。
如图:
当 队头和队尾相等的时候,循环队列为空。
代码示例:
//判空
bool CQueueIsEmpty(CQueue* que)
{
assert(que);
return que->front == que->rear;
}
2.队列为满
判断队列为满条件
代码:
//判满
bool CQueueIsFull(CQueue* que)
{
assert(que);
return (que->rear + 1) % (que->capacity + 1) == que->front;
}
关键在于多开辟一个辅助空间才能区分满和空两种情况。
2.代码示例
1. 声明
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
//循环队列 数组实现
typedef int DataType;
typedef struct CircularQueue
{
DataType* arr;
int front;
int rear;
int capacity;
}CQueue;
//-----------------接口------------------
//初始化
CQueue* CQueueInit(int sz);
//销毁
void CQueueDestroy(CQueue* que);
//入队
void CQueuePush(CQueue* que, DataType val);
//出队
void CQueuePop(CQueue* que);
//队头 为空返回-1
DataType CQueueFront(CQueue* que);
//队尾 为空返回-1
DataType CQueueRear(CQueue* que);
//判空
bool CQueueIsEmpty(CQueue* que);
//判满
bool CQueueIsFull(CQueue* que);
2. 实现
//初始化
CQueue* CQueueInit(int sz)
{
CQueue* que = (CQueue*)malloc(sizeof(CQueue));
assert(que);
que->arr = (DataType*)malloc(sizeof(int) * (sz + 1));
assert(que->arr);
que->capacity = sz;
que->front = que->rear = 0;
return que;
}
//销毁
void CQueueDestroy(CQueue* que)
{
assert(que);
free(que->arr);
free(que);
}
//入队
void CQueuePush(CQueue* que, DataType val)
{
assert(que);
if (CQueueIsFull(que))
return;
que->arr[que->rear] = val;
que->rear++;
que->rear %= (que->capacity + 1);
}
//出队
void CQueuePop(CQueue* que)
{
assert(que);
if (CQueueIsEmpty(que))
return;
que->front++;
que->front %= (que->capacity + 1);
}
//队头
DataType CQueueFront(CQueue* que)
{
assert(que);
if (CQueueIsEmpty(que))
return -1;
return que->arr[que->front];
}
//队尾
DataType CQueueRear(CQueue* que)
{
assert(que);
if (CQueueIsEmpty(que))
return -1;
int prev = que->rear - 1;
if (prev == -1)
prev = que->capacity;
return que->arr[prev];
}
//判空
bool CQueueIsEmpty(CQueue* que)
{
assert(que);
return que->front == que->rear;
}
//判满
bool CQueueIsFull(CQueue* que)
{
assert(que);
return (que->rear + 1) % (que->capacity + 1) == que->front;
}