队列是另一种限定性的线性表,他只允许在表的一端插入元素,而在表的另一端删除元素,具有“先进先出”的特点。在队列中,允许插入的一端称为队尾,允许删除的一端称为队首。
与线性表相似,队列也有两种存储结构:顺序队列和链式队列。
一,顺序队列
顺序队列使用顺序表来实现的,即队列中的元素均存放在一片连续的内存空间中。通过该片内存的地址对队列中元素进行访问。之前是用数组来实现顺序表的。通过数组名访问数组元素。数组的长度必须提前设定,一旦超过设定的大小,则无法再向其中添加元素。
这里采用与顺序栈类似的方法,通过设定初始值来动态申请内存,当内存不够用时,修改初始值来再次申请更大的内存达到扩容的目的。所以可以通过动态申请的内存地址来访问队列中的元素。
因此,以下实现的是可以扩容的顺序队列。
1. 顺序队列的结构
要实现扩容的顺序队列,
(1)首先要动态申请一片连续的内存。该内存需要一个指针data指向,通过该指针来访问该内存。
(2)而该内存的大小需提前设定,用capacity进行表示
(3)另外,还需要知道队列中实际元素的个数size
因为队列具有“先进先出”的特点,只能在一端(队尾)进,另一端(队头)出。所以可能造成下面的情况:
此时,需要时刻知道队列两端所在的位置,但又不能像顺序栈一样用size来表示队尾结点所在位置。所以还需要两个变量:(4)head表示队首结点所在的下标
(5)tail表示队尾结点的下个位置所在的下标(这样入队时直接在tail处设置元素即可)。
所以,队列中所有元素的下标所在范围为:[head,tail),如下图:
代码如下:
typedef char SeqQueueType;
//顺序队列的结构
typedef struct SeqQueue
{
SeqQueueType* data;//指向顺序队列的指针
int size;//顺序队列的实际长度
int capacity;//顺序队列的有效长度
int head;//顺序队列的头节点所在的下标
int tail;//顺序队列尾节点下个元素所在的下标,即[head,tail)
}SeqQueue;
2. 顺序队列的初始化
在对队列初始化时,首先要设定队列有效长度的初始值,再根据该初始值来动态申请内存,并由data指向。因为此时队列中并没有元素,所以,实际长度size,head和tail均置为0即可。
代码如下:
//初始化顺序队列
void SeqQueueInit(SeqQueue* queue)
{
if(queue == NULL)
{
//非法输入
return;
}
queue->size = 0;//初始时队列为空
queue->capacity =1000;//设置有效长度为1000
queue->data = (SeqQueueType*)malloc(queue->capacity*sizeof(SeqQueueType));//动态申请内存,由data指向
queue->head = 0;//初始时,队列为空