MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。来源:力扣(LeetCode)
这是来自力扣的一道题,要求模拟一个循环队列,包含以上的功能。这里的循环队列有固定的长度为k,队满就不能再入数据。
一般队列都是用链表来模拟实现的,那么这里的循环队列也可以用链表实现,只不过要注意一些地方:
这种情况下,如果设置头尾指针front和rear,k==4,那么此时队列判空和判满的条件都是rear==front,所以为了优化这个情况,我们可以多开一个空间来便于判断队空和队满:
此时k==5,当rear==front时为队空,rear->next==front时为队满。但是这种情况又有一个问题就是队尾该如何取,已知rear是在存完数据后++,所以一直指向空位置,在单链表要想取rear的前一个位置就要再多加一个指针rearpre来取rear前一个位置或者也可以用双向链表来实现。
而如果这里使用数组来模拟这个队列,思想是和链表一样的,而且操作更加简单,所以这里我选择用数组来模拟:
class MyCircularQueue {
public:
MyCircularQueue(int k) {
a = (int*)malloc(sizeof(int) * (k + 1)); //比原来多开一个空间
front = 0;
rear = 0;
m = k;
}
bool enQueue(int value) {
if (isEmpty())
{
a[rear] = value;
rear++;
return true;
}
if (isFull())
return false;
if (rear == m + 1)
{
rear = 0;
a[rear] = value;
rear++;
}
else
{
a[rear] = value;
rear++;
}
return true;
}
bool deQueue() {
if (isEmpty())
return false;
if (front == m + 1)
{
front = 0;
front++;
}
else
{
front++;
}
return true;
}
int Front() {
if (isEmpty())
return -1;
return a[front];
}
int Rear() {
if (isEmpty())
return -1;
return a[(rear - 1 + m + 1) % (m + 1)]; 取模防止越界
}
bool isEmpty() {
return rear == front;
}
bool isFull() {
return (rear + 1) % (m + 1) == front; //取模防止越界
}
int* a; //模拟循环链表的队列
int front; //指向头
int rear; //指向尾
int m; //要求数组长度
};
用数组模拟判断队满时要注意用rear+1==front判断有一种特殊情况会越界:
此时的rear+1会到下标为5的位置处去导致越界,可以通过特殊处理解决,也可以改一下判断条件为(rear + 1) % (k + 1) == front,这样rear在下标4以前的位置模5不会改变,而在下标为4的地方便会回到下标为0处。
判断队尾时用rear-1也有一种特殊情况会越界:
此时rear-1会到下标为-1的位置导致越界 ,这里也可以通过特殊处理解决,不过也同样可以改变判断条件为(rear-1+k+1) % (k+1)。