图一:线性队列 图二:环形队列
一、线性队列和环形队列的比较
我们通常在使用队列的时候,在线性和环形两者之中,我们通常会选择环形,并且在书中,我们也最常见的是环形队列,有没有想过这是为什么呢?接下来就让我们来谈谈why和how。
这个算法效率高不高,我们通常会考虑它的时间复杂度,在线性队列中,入队和出队的时间复杂度分别为O(1)和O(n),而环形队列又可以说成顺序表是环形的,实际是用顺序表实现环形队列。它的入队和出队时间复杂度均为O(1),所以环形的目的是为了提高出队的时间复杂度。细心的同学会发现,在图二中浪费了一个单元不使用,这是为了区分队空和队满。在下面的代码中会提到。
二、深入了解环形队列
front队头:第一个元素的下标
rear队尾:最后一个元素的下一个下标
队满:(rear+1)%n==front {可以与魔方阵的算法思想联系起来}
队空: front==rear
首先,我们要学会定义一个结构体,这个环形队列中就包括了数据,front,rear
#define SIZE 10
typedef struct SQueue
{
int elem[SIZE];
int front;//队头指针,第一个元素的下标
int rear;//队尾指针,最后一个元素的下一个下标,当前可以存放数据的下标
}SQueue,*PSQueue;
//初始化
void InitQueue(PSQueue ps)
{
assert(ps != NULL);
if(ps == NULL)
{
return ;
}
ps->front = 0;
ps->rear = 0;
}
//判满
static bool IsFull(PSQueue ps)
{
return (ps->rear+1)%SIZE == ps->front;//
}
//入队
bool Push(PSQueue ps,int val)
{
if(IsFull(ps))
{
return false;
}
ps->elem[ps->rear] = val;
ps->rear = (ps->rear+1)%SIZE;
return true;
}
//获取队头的值,但不删除
bool GetTop(PSQueue ps,int *rtval)
{
if(IsEmpty(ps))
{
return false;
}
if(rtval != NULL)
{
*rtval = ps->elem[ps->front];
}
return true;
}
//获取队头的值,且删除
bool Pop(PSQueue ps,int *rtval)
{
if(IsEmpty(ps))
{
return false;
}
if(rtval != NULL)
{
*rtval = ps->elem[ps->front];
}
int *p=ps->front;
ps->front=p->front;
free(p);
return true;
}
//判断队空
bool IsEmpty(PSQueue ps)
{
return front==rear;
}