方法一:数组
1.1
这是最原始的版本,只是在用数组实现的非循环队列的代码上添加一些代码,这个方法的enQueue,deQueue和Rear代码实现有点繁琐
class MyCircularQueue
{
private:
int* contents; //动态数组用于存放数据
int head; //记录队首元素的下标
int tail; //记录队尾元素的下标
int items; //记录队列中现有的元素个数
const int maxSize; //队列最大容量
public:
MyCircularQueue(int k)
: maxSize{ k }, items{ 0 }, head{ 0 }, tail{ 0 }
{
contents = new int[maxSize];
}
bool isEmpty()
{
return items == 0;
}
bool isFull()
{
return items == maxSize;
}
bool enQueue(int value)
{
if (isFull() == true)
{
return false;
}
contents[tail] = value;
items++;
if (tail == maxSize - 1) //如果这里为true,说明数组最后一个元素已经被填上了,
{ //为了循环起来,我们要让tail=0,即回到了数组最前面
tail = 0;
}
else
{
tail++; //否则,我们将tail++,注意我们已经将新元素入队了
} //所以现在tail存储的是队尾元素之后的那个元素的下标
return true;
}
bool deQueue()
{
if (isEmpty() == true)
{
return false;
}
if (isEmpty() == false)
{
if (head == maxSize - 1) //这里与前面同理
{
head = 0;
}
else
{
head++;
}
items--;
}
return true;
}
int Front()
{
if (isEmpty() == false)
{
return contents[head];
}
return -1;
}
int Rear()
{
if (isEmpty() == false)
{
if (tail == 0) //因为我们的tail其实是存储的是队尾元素之后的那各元素的下标
{
return contents[maxSize - 1]; //因此如果tail==0,说明队尾元素在数组最后
}
else
{
return contents[tail - 1]; //不然就得tail-1
}
}
return -1;
}
};
1.2
我们改进了enQueue,deQueue和Rear的代码实现,用一种统一的方法(取余)来判断head或者tail
class MyCircularQueue
{
private:
int* contents; //动态数组用于存放数据
int head; //记录队首元素的下标
int tail; //记录队尾元素的下标
int items; //记录队列中现有的元素个数
const int maxSize; //队列最大容量
public:
MyCircularQueue(int k)
: maxSize{ k }, items{ 0 }, head{ 0 }, tail{ 0 }
{
contents = new int[maxSize];
}
bool isEmpty()
{
return items == 0;
}
bool isFull()
{
return items == maxSize;
}
bool enQueue(int value)
{
if (isFull() == true)
{
return false;
}
contents[tail] = value;
items++;
tail = (tail + 1) % maxSize; //我们通过这种取余的方法,一条语句就可以包含需要“循环”tail和不需要的情况
return true;
}
bool deQueue()
{
if (isEmpty() == true)
{
return false;
}
items--;
head = (head + 1) % maxSize; //这里与上面同理
return true;
}
int Front()
{
if (isEmpty() == false)
{
return contents[head];
}
return -1;
}
int Rear()
{
if (isEmpty() == false)
{
return contents[(tail - 1 + maxSize) % maxSize]; //同理
}
return -1;
}
};
1.3
在1.2的基础上,去掉items这个数据成员,就得到了1.3
这个方法技巧性最强,因为不再使用一个数据成员来记录当前队列中元素的个数,所以当tail==head时,说明队列为空
我们规定只用maxSize-1个空间来存储元素,这样((tail + 1) % maxSize) == head就可以判断队列是否满了
队列中元素个数items=(tail-head+maxSize) %maxSize
class MyCircularQueue
{
private:
int* contents; //动态数组用于存放数据
int head; //记录队首元素的下标
int tail; //记录队尾元素的下标
const int maxSize; //队列最大容量
public:
MyCircularQueue(int k)
: maxSize{ k + 1 }, head{ 0 }, tail{ 0 } //如果不将k+1,会少一个空间
{
contents = new int[maxSize];
}
bool isEmpty()
{
return tail == head; //比如说刚开始还没有元素入队,这时tail=head=0
}
bool isFull()
{
return ((tail + 1) % maxSize) == head;
}
bool enQueue(int value)
{
if (isFull() == true)
{
return false;
}
contents[tail] = value;
tail = (tail + 1) % maxSize;
return true;
}
bool deQueue()
{
if (isEmpty() == true)
{
return false;
}
head = (head + 1) % maxSize;
return true;
}
int Front()
{
if (isEmpty() == false)
{
return contents[head];
}
return -1;
}
int Rear()
{
if (isEmpty() == false)
{
return contents[(tail - 1 + maxSize) % maxSize];
}
return -1;
}
};
方法二:链表
其实就是正常的用链表实现队列
class MyCircularQueue
{
private:
class Node
{
public:
int item;
Node* next;
Node(const int i) :item{ i }, next{ nullptr } {}
};
Node* head;
Node* tail;
int items;
const int maxSize;
public:
MyCircularQueue(int k)
: maxSize{ k }
{
head = tail = nullptr;
items = 0;
}
bool isEmpty()
{
return items == 0;
}
bool isFull()
{
return items == maxSize;
}
bool enQueue(int value)
{
if (isFull() == true)
{
return false;
}
Node* newNode = new Node(value);
items++;
if (head == nullptr)
{
head = newNode;
}
else
{
tail->next = newNode;
}
tail = newNode;
return true;
}
bool deQueue()
{
if (isEmpty() == true)
{
return false;
}
items--;
Node* temp = head;
if (items == 0)
{
head = tail = nullptr;
}
else
{
head = head->next;
}
delete temp;
return true;
}
int Front()
{
if (isEmpty() == true)
{
return -1;
}
return head->item;
}
int Rear()
{
if (isEmpty() == true)
{
return -1;
}
return tail->item;
}
};