目录
循环队列初始化(myCircularQueueCreate):
循环队列是否为空(myCircularQueueIsEmpty):
循环队列是否为满(myCircularQueueIsFull):
循环队列插入元素(myCircularQueueEnQueue):
循环队列删除元素(myCircularQueueDeQueue):
从队首获取元素(myCircularQueueFront):
题目:
理论来讲本题用数组和链表都可以,不过为了方便,这里就只说数组的方法。(C语言实现)
剖析:
我们可以先定义一个front(头)和rear(尾)(从0开始的下标),每插入一个元素就把rear往后一位(rear指向的是已有元素的下一个位置,也就是下一次插入元素的位置),每删除一个元素就把front往前一位,但如果直接直接定义k个元素的数组,就会出现下面这种情况
左边是一直插入元素,直到队列被插满,此时front==rear
右边是插入元素后开始删除元素,直到队列为空,此时front==rear
那么front==rear时到底是队列为满还是队列为空呢?
判断为满:
其实只要创建k+1个元素的数组,就能解决上述问题。
还是以上面k=4为例,那么数组就有5个元素,当rear的下一个就是front时,即为满,以下是几个满的例子:
第二和第三种情况还好说,只需要判断(rear+1)==front就行,但第一种rear+1不就成了5了?5!=0,还是会被判断成没满,我们来看下面的公式:
rear的下一个位置模除数组的元素个数,这样即使rear超出了范围也会自动回到开头,我们将上面三个例子代入可得
(4+1)%(4+1)=0,front也为0,可判断为满
(0+1)%(4+1)=1,front也为1,可判断为满
(1+1)%(4+1)=2,front也为2,可判断为满
判断为空:
判断是否为空就简单了,也就是上面说的
举个例子:
此时front删掉了最后一个元素,与rear相等,即为空。
空和满的循环队列逻辑图:
删除元素:
先来看以下两种删除元素的场景:
第二种情况删除元素时只需要front+1就可以,但第一种元素front+1就成了5,所以又要用到插入元素时的公式:
front+1即为删除一个元素后front的值,此时再模除数组大小,这样即使超出范围也会自动回到开头,我们将上面两个例子代入可得
front=(4+1)%(4+1)=0,此时front走到了尽头,自动回到开头
front=(1+1)%(4+1)=2,此时front往前移一位,代表删除一个元素
实战:
循环队列结构体(MyCircularQueue):
_a负责存放数据,front是头下标,rear是尾指针,_k为创建的队列大小
typedef struct
{
int* _a;
int _front;
int _rear;
int _k;
} MyCircularQueue;
循环队列初始化(myCircularQueueCreate):
这里qe和qe->_a都以malloc创建的原因是malloc创建的变量存在动态区,但普通的局部变量都在栈区,栈区的变量等函数体结束后就销毁了
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* qe=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
qe->_a=(int*)malloc(sizeof(int)*(k+1));
qe->_front=0;
qe->_rear=0;
qe->_k=k;
return qe;
}
循环队列是否为空(myCircularQueueIsEmpty):
如上面所说,若rear和front相等,则为空,否则不为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->_rear==obj->_front;
}
循环队列是否为满(myCircularQueueIsFull):
这时就用到了上面提到的公式
如果公式成立,则为满,否则为非满
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
return (obj->_rear+1)%(obj->_k+1)==obj->_front;
}
循环队列插入元素(myCircularQueueEnQueue):
这里复用了上面写的判断循环队列是否为满的函数,如果为满则无法插入,返回false,否则插入元素并返回真,
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if(myCircularQueueIsFull(obj))
return false;
obj->_a[obj->_rear]=value;
obj->_rear++;
obj->_rear=obj->_rear%(obj->_k+1);//上面的公式
return true;
}
循环队列删除元素(myCircularQueueDeQueue):
这里复用了上面写的判断循环队列是否为空的函数,如果为空则无法删除,返回false,否则删除元素并返回true
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return false;
obj->_front++;
obj->_front=obj->_front%(obj->_k+1);//上面的公式
return true;
}
从队首获取元素(myCircularQueueFront):
这里复用了上面写的判断是否为空的函数,按照题意,如果为空返回-1,否则返回队首的值
int myCircularQueueFront(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->_a[obj->_front];
}
从队尾获取元素(myCircularQueueRear):
首先和上一个函数一样,是一个复用,用来判断是否为空,如果不是空,就返回队尾元素
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
int tail=obj->_rear-1;
if(tail==-1)//如果rear在数组的0下标处,再减就会成-1,此时返回数组的最后一个位置的元素
return obj->_a[obj->_k];
return obj->_a[tail];
}
}
释放循环队列(myCircularQueueFree):
先释放_a再释放obj,否则如果先释放obj就找不到_a了
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->_a);
free(obj);
}
结果:
所以最终代码为:
typedef struct
{
int* _a;
int _front;
int _rear;
int _k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* qe=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
qe->_a=(int*)malloc(sizeof(int)*(k+1));//多开一个
qe->_front=0;
qe->_rear=0;
qe->_k=k;
return qe;
}
bool myCircularQueueIsFull(MyCircularQueue* obj);//在这声明是因为这两个函数在最下面,不声明的话找不到
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if(myCircularQueueIsFull(obj))
return false;
obj->_a[obj->_rear]=value;
obj->_rear++;
obj->_rear=obj->_rear%(obj->_k+1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return false;
obj->_front++;
obj->_front=obj->_front%(obj->_k+1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->_a[obj->_front];
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
int tail=obj->_rear-1;
if(tail==-1)//如果rear在数组的0下标处,再减就会成-1,此时返回数组的最后一个位置的元素
return obj->_a[obj->_k];
return obj->_a[tail];
}
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->_rear==obj->_front;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
return (obj->_rear+1)%(obj->_k+1)==obj->_front;
}
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->_a);
free(obj);
}