队列的基本实现(顺序队列、循环队列)

目录

一、队列的简介

二、顺序队列

三、循环队列


一、队列的简介

          队列:一种只允许在一端进行插入操作,在另一端进行删除操作的特殊线性表。(先进先出)

          如图所示为队列的示意图

                         

        队列的分类

                  1、顺序队列:创建顺序队列需申请一块连续的内存空间(动态 / 静态申请),使用两个指针进行管理。一个指针 front 指向队头元素,一个指针 rear 指向队尾元素后一位置,即下一次入队的元素存储的位置。有两种出队操作,下面对这两种方式进行比较,了解其中优劣。

                   

                    上述两种方法,操作步骤是相同的,只是队头指针的操作不同,通过示意图我们发现:

                       对于方法(1),每次出队,所有元素都需要向前移动一位,如果多次出队,就需要多次移动大量数据;

                       对于方法(2),我们可以很明显的发现,每出队一个数据,数列中就会有一个位置失去它的是有价值,比如说在上述情况下,我们再进队 F G ,而队列此时只有一个元素的位置,所以只有 F 可以实现入队,而 G 会因为队满而无法入队,事实上我们发现,队列并没有满,但是却无法入队,我们称之为假溢出

                  2、循环队列:头尾相接的顺序队列

                          

                        我们发现循环队列解决了“假溢出”,需要注意的是判空与判满。

二、顺序队列

        下面实现的顺序队列,使用动态开辟空间的方法实现,出队使用上述所说的第二种方法。

1、定义

typedef int DataType;

typedef struct QueueNode
{
	DataType _data;
	struct QueueNode* _next;
}QueueNode;

typedef struct Queue
{
	QueueNode* _front;
	QueueNode* _rear;
}Queue;

2、入队

static QueueNode* BuyQueueNode(DataType d)
{
	QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
	assert(newNode);
	
	newNode->_data = d;
	newNode->_next = NULL;
	return newNode;
}

void QueuePush(Queue* pq, DataType d)
{
	assert(pq);

    // 判断队列是否为空
	if (pq->_front == NULL)
	{
		pq->_front = pq->_rear = BuyQueueNode(d); 
	}
	else
	{
		QueueNode* rear = BuyQueueNode(d);
		pq->_rear->_next = rear;
		pq->_rear = rear;
	}
}

 3、出队

// 出队选择第二种方法,即队头不固定位置,通过动态实现顺序队列来避免假溢出,但会浪费一些空间
void QueuePop(Queue* pq)
{
	QueueNode* next = NULL;
	
	assert(pq);

	next = pq->_front->_next;

	free(pq->_front);
	pq->_front = next;
}

4、其他接口 

#include "Queue.h"

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

	pq->_front = NULL;
	pq->_rear = NULL;
}

void QueueDestory(Queue* pq)
{
	QueueNode* cur = pq->_front;

	assert(pq);

	while (cur != NULL)
	{
		QueueNode* next = cur->_next;
		free(cur);
		cur = next;
	}
	pq->_front = NULL;
	pq->_rear = NULL;
}

DataType QueueFront(Queue* pq)
{
	assert(pq);

	return pq->_front->_data;
}

int QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->_front == NULL ? 0 : 1;  //空 0   非空 1
}

int QueueSize(Queue* pq)
{
	int size = 0;
	QueueNode* cur = NULL;

	assert(pq);

	cur = pq->_front;
	while (cur)
	{
		size++;
		cur = cur->_next;
	}
	return size;
}

三、循环队列

         上面我们已经说了循环队列解决了“假溢出”的问题,我们在下面的定义中,只定义了队列最大可容纳的数据为6,实际上最大元素个数为5,循环队列中,始终有一个元素的位置用来让我们判断队空与队满。

1、定义

#define maxSize 6
typedef int DataType;

typedef struct CirQueue{
	DataType* data;
	int front;
	int rear;
}CirQueue;

2、入队

void CirQueuePush(CirQueue* pcq, DataType d)
{
	if (CirQueueFull(pcq))
	{
		printf("队列已满,无法入队数据\n");
	}
	else
	{
		pcq->data[pcq->rear + 1] = d;
		pcq->rear = (pcq->rear + 1) % maxSize;
	}
}

 3、出队

void CirQueuePop(CirQueue* pcq)
{
	if (!CirQueueEmpty(pcq))
	{
		printf("队列为空,无可出队数据\n");
	}
	else
	{
		pcq->front = (pcq->front + 1) % maxSize;
	}
}

4、其他接口

void CirQueueInit(CirQueue* pcq)
{
	pcq->data = (DataType*)malloc(sizeof(DataType)*maxSize);
	assert(pcq->data);

	pcq->front = 0;
	pcq->rear = 0;
}

void CirQueueDestory(CirQueue* pcq)
{
	free(pcq->data);
	pcq->data = NULL;
}

DataType CirQueueFront(CirQueue* pcq)
{
	assert(pcq);

	return pcq->data[(pcq->front + 1) % maxSize];
}

int CirQueueFull(CirQueue* pcq)
{
	assert(pcq);
	return pcq->front == (pcq->rear + 1) % maxSize ? 1 : 0;	// 满 1  不满 0
}

int CirQueueEmpty(CirQueue* pcq)
{
	assert(pcq);
	return (pcq->front == pcq->rear) ? 0 : 1;	// 空 0  非空 1
}

int CirQueueSize(CirQueue* pcq)
{
	if (CirQueueFull(pcq))
	{
		return maxSize - 1;
	}
	return pcq->rear - pcq->front > 0 ? pcq->rear - pcq->front : pcq->front - pcq->rear;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值