队列的定义和特点以及循环队列的实现

一.队列的定义和特点

队列是一种先进先出(First In First Out)的线性表。它只允许在表的一端进行插入,而在另一端删除数据。允许插入的一端称为队尾(rear),允许删除的一端则称为队头(front)。队列与日常生活中的排队是一样的,先进入队列的元素最早离开。

队列的示意图

通过对队列示意图的观察,发现可以用类似数组的方式来实现队列,定义两个指针,一个指针phead用来表示队头,一个指针ptail用来表示队尾。具体的代码实现如下:


#pragma once
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>


typedef int QDataType;
typedef struct QueueNode
{
	int val;
	struct QueueNode* next;
}QNode;
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;
//初始化
void QueueInit(Queue* pq);
//销毁
void QueueDestroy(Queue* pq);
// 入队列
void QueuePush(Queue* pq, QDataType x);
// 出队列
void QueuePop(Queue* pq);
//取队头数据
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
//判空
bool QueueEmpty(Queue* pq);
//队列的数据总数
int QueueSize(Queue* pq);



void QueueInit(Queue* pq)
{
	assert(pq);

	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);

		cur = next;
	}

	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

// 入队列
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}

	newnode->val = x;
	newnode->next = NULL;

	if (pq->ptail)
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	else
	{
		pq->phead = pq->ptail = newnode;
	}

	pq->size++;
}

// 出队列
void QueuePop(Queue* pq)
{
	assert(pq);

	// 0个节点 
	assert(pq->phead != NULL);

	// 一个节点
	// 多个节点
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		QNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq); 
	assert(pq->phead != NULL);
	return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail != NULL);
	return pq->ptail->val;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

二.循环队列的实现

循环队列是把顺序队列首尾相连,把存储队列元素的表从逻辑上看成一个环,成为循环队列。循环队列就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用。

 循环队列示意图

可以把该循环队列示意图看成一个首尾相连的数组,当队列满且要插入数据,将Tail指针指向回0下标,这样就形成了一个循环队列。

如果像以往一样,有n个数据开n个空间,那么队空和队满的条件分不清,因为队空和队满都用front==rear表示。因此可以采用n个数据开n+1个空间的方法,让front指针指向队头数据,rear指针指向队尾数据的下一位。这样就可以令front==rrear表示队空,front==(rear+1)%(n+1)表示队满。

代码实现如下:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef struct {
    int* queue;
    int front;
    int rear;
    int n;
} MyCircularQueue;

//创建一个可以存放n个元素的循环队列,实际申请的空间为n + 1
MyCircularQueue* myCircularQueueCreate(int n) {
    MyCircularQueue* pcq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    pcq->queue = (int*)malloc(sizeof(int) * (n + 1));
    pcq->front = 0;
    pcq->rear = 0;
    pcq->n = n;

    return pcq;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //判满
    if ((obj->rear + 1) % (obj->n + 1) == obj->front)
    {
        return false;
    }
    //队尾入队
    obj->queue[obj->rear++] = value;
    //如果队尾越界,更新为最小值
    if (obj->rear == obj->n + 1)
        obj->rear = 0;

    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    //判空
    if (obj->front == obj->rear)
        return false;
    //队头出队
    ++obj->front;
    //如果队头越界,更新为最小值
    if (obj->front == obj->n + 1)
        obj->front = 0;

    return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
    if (obj->front == obj->rear)
        return -1;
    else
        return obj->queue[obj->front];
}


int myCircularQueueRear(MyCircularQueue* obj) {
    if (obj->front == obj->rear)
        return -1;
    //队尾元素再rear索引的前一个位置,如果rear为0,
    //则队尾元素在数组的最后一个位置
    if (obj->rear == 0)
        return obj->queue[obj->n];
    else
        return obj->queue[obj->rear - 1];
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front == obj->rear;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear + 1) % (obj->n + 1) == obj->front;
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->queue);
    free(obj);
}

上述是我个人的理解,如有错误,望各位帮忙指正。

  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过客吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值