我们来看数据结构中的队列结构
现在我们看到的线性结构基本上就有2最终实现方案,一种是顺序实现,另一种就是链式实现。
首先我们来看顺序队列的实现方案。
还是定义结构体,首先就是结构体成员的分析,队列结构是先进先出式的结构,和栈结构恰恰相反。比栈结构稍微复杂的一点就是队列结构不但需要记录头部,还要记录尾部。所以我们相对于栈也就自然多了一个成员,就是记录尾部的指针(**这里的指针是所谓的广义上的指针,不一定必须是指针类型的,可以是一个记录位置的下标,当然指针也完全可以)。**成员依旧有记录这个队列空间容量的size_t类型的成员capacity,当然也会有指向这个空间的base指针(int*类型),还有记录队列头和尾部的指针。结构体自然就定义出来了。
typedef struct SeqQueue
{
int capacity;
int* base;
int top;
int tail;
}SeqQueue;
我们还是规定下标从0开始,因为从0开始号处理判断是否队列为空,当然从-1开始完全可以。
首先就是队列的初始化还有判断队列满与空
bool SeqQueueInit(SeqQueue* pst,int size)
{
pst->capacity = size > DEFAULT_CAPACITY ? size : DEFAULT_CAPACITY;
pst->base = (int*)malloc(sizeof(SeqQueue)*pst->capacity);
if (pst->base == NULL)
return false;
pst->top = pst->tail = 0;
return true;
}//这里我们让下标从-1开始
bool SeqQueueIsFull(SeqQueue* pst)
{
return pst->top >= pst->capacity;
}
bool SeqQueueIsEmpty(SeqQueue* pst)
{
return pst->top == pst->tail;
}
void SeqQueuePush(SeqQueue* pst, int x)
{
if (SeqQueueIsFull(pst))
{
printf("队列已经满了,不能继续插入\n");
}
pst->base[pst->top++] = x;
}
在判断队列空的时候判断的是头尾指针是否相等,判断队列满的时候是判断头指针是否大于队列的实际容量。
出队列的时候需要进行的操作
int GetSeqQueueTop(SeqQueue* pst)
{
if (SeqQueueIsEmpty(pst))
{
printf("栈已空不能继续出栈顶元素");
}
return pst->base[pst->tail++];
}
再来看将队列展示出来
(从头到尾)
void SeqQueueShow(SeqQueue* pst)
{
for (int i = pst->tail; i < pst->top; i++)
{
printf("%d ", pst->base[i]);
}
}
最容易出错的就是销毁队列,不但要释放掉这个队列的空间,为了规避野指针,还要最后将base指针指向空。
void DestoryQueue(SeqQueue* pst)
{
free(pst->base);
pst->base = NULL;
pst->capacity = pst->tail = pst->top = 0;
}
顺序队列基本操作就已经完成了,接下来我们来看循环队列
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
循环队列相比较队列就难搞很多,首先向这个队列怎么让他循环起来,如果没见过,还真的不好想怎么让这个队列循环起来。**我们来看之前学习时候,如果让一堆数据在一串固定范围内,我们经常采用的是取余。在此我们也用取余运算让插入的数据在这个队列空间内。**但是一旦使用循环队列后会出现很多不好解决的问题,如何区别队列空间满了还是空,如何正确插入到空的队列空间。接下来我们引进一种新的思想解决。一起来看。
我们插入数据的时候只要这个队列有空的空间就会继续在这个队列空间内插入,这就会带来一个问题,判断空和判断满的条件是一样的,都是队头指针和队尾指针相等,这时候就需要用到一个算法,我们需要将一个空间空出来用来区分队列满换个队列空。也就是说我们少用一个空间来将队列判满和判空区别开来。
来看代码
首先还是需要搭建出循环队列的结构
typedef struct CycleQueue
{
int* base;
int top;
int bottom;
int capacity;
}CycleQueue;
void CycleQueueInit(CycleQueue* pst,int sz)
{
pst->capacity = pst->capacity > sz ? sz : pst->capacity;
pst->base = (int*)malloc(sizeof(CycleQueue)*pst->capacity);
pst->top = pst->bottom = 0;
}
盘满判空函数的创建
bool CycleQueueIsFull(CycleQueue* pst)
{
return (pst->top + 1) % pst->capacity == pst->bottom;
}
bool CycleQueueIsEmpty(CycleQueue* pst)
{
return (pst->top) % pst->capacity == pst->top;
}
在循环队列中最难的点就是出队,很多因素非常容易忽略掉
int GetCycleQueue(CycleQueue*pst)
{
if (CycleQueueIsEmpty(pst))
{
return false;
}
return pst->base[pst->bottom++];
}
基本上剩余的操作和顺序队列相差不大。主要就是注意这个出队后这个队列底的指针可不是原先从零开始,这里需要多加注意。