数据结构之 ---- 循环队列

系列文章目录


前言

队列这个数据结构大家都很熟悉了,本质其实就是一个入数据只能在尾入,出数据只能在头出的顺序表。


一、顺序队列的缺点


进行入队操作时,和顺序表一样,直接在队列尾部插入数据,时间复杂度为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;
}

Guess you like

Origin blog.csdn.net/juggte/article/details/119659544