队列可以分为顺序队列,循环队列以及链队列
顺序队列:
(1)如果队首元素删除之后,所有元素不移动,那么入队和出队操作的时间复杂度是O(1)
(2)如果队首元素删除之后,所有元素都要往前移动一位,那么入队的时间复杂度是O(1),出队的复杂度是O(n)
第一种做法在时间复杂度上比第二种做法要优越,但是可能会发生"假溢出",也就是数组的低端还有空闲位置,但是数组的高端却被插满了
循环队列:
循环队列则可以很好地解决"假溢出"这个问题,当数组高端满了之后,可以将队尾指针指向数组低端位置,这样就可以解决"假溢出"问题
其中,判断队满的条件是(rear+1)%queueSize==front,这样做虽然浪费了一个数组元素空间,但是减少了时间代价。判断队空的条件是rear=front
可以想出,判断队满的条件也可以是rear=front,但是如此做的话,会让判断队空和判断队满的条件重复,因此需要牺牲一个数组元素空间来判断队满
链队列:
链队列为了操作的方便,会设置一个头结点,然后用队头指针指向链队列的头结点,队尾指针指向终端结点
循环队列代码如下:
#include<iostream>
#include<string>
using namespace std;
const int queueSize = 10;
template<typename T>
class CirQueue
{
private:
int front, rear;
T data[queueSize];
public:
CirQueue();
void insertQueue(T x);//入队
T exitQueue();//出队
T getQueueHead();//得到队首元素
bool empty();//判断是否为空
void printQueue();//打印出队列里面的元素
};
template<typename T>
CirQueue<T>::CirQueue()
{
front = rear = queueSize - 1;
}
template<typename T>
void CirQueue<T>::insertQueue(T x)
{
if ((rear + 1) % queueSize == front)//插入元素前需要判断队列是否已经满了
{
throw exception("插入元素时发生了上溢");
}
rear = (rear + 1) % queueSize;
data[rear] = x;
}
template<typename T>
T CirQueue<T>::exitQueue()
{
if (front == rear)
{
throw exception("删除队首元素时发生了下溢");
}
front = (front + 1) % queueSize;
return data[front];
}
template<typename T>
T CirQueue<T>::getQueueHead()
{
if (front == rear)
{
throw exception("获取队首元素时发生了下溢");
}
int x = (front + 1) % queueSize;
return data[x];
}
template<typename T>
bool CirQueue<T>::empty()
{
if (front == rear)
{
return true;
}
return false;
}
template<typename T>
void CirQueue<T>::printQueue()
{
if (front == rear)
{
throw exception("队列已空,无法打印元素");
}
front = (front + 1) % queueSize;
while (front != rear)
{
cout << data[front] << endl;
front++;
}
cout << data[front];
}
int main()
{
CirQueue<int> cirQueue;
try
{
cirQueue.insertQueue(1);
cirQueue.insertQueue(10);
cirQueue.insertQueue(100);
cirQueue.insertQueue(1000);
cout << "删除队首元素:" << cirQueue.exitQueue() << endl;
cout << "得到队首元素:" << cirQueue.getQueueHead() << endl;
cout << cirQueue.empty();
cirQueue.printQueue();
}
catch (exception e)
{
cout << e.what() << endl;
}
return 0;
}
链队列的代码如下:
#include<iostream>
using namespace std;
template<typename T>
class Node
{
public:
T data;
Node<T>*next;
Node() :next(nullptr) {};
};
template<typename T>
class LinkQueue
{
private:
Node<T>*front, *rear;
public:
LinkQueue();
~LinkQueue();
void insertQueue(T x);
T deQueue();
T getHead();
void printQueue();
bool empty();
};
template<typename T>
LinkQueue<T>::LinkQueue()//初始化链队列,将front指针和rear指针都指向头结点
{
Node<T> *s = new Node<T>();
front = rear = s;
}
template<typename T>
LinkQueue<T>::~LinkQueue()
{
while (front != rear)
{
Node<T>*p = new Node<T>();
p = front;
front = front->next;
delete p;
}
delete front;
}
template<typename T>
void LinkQueue<T>::insertQueue(T x)//链队列的插入
{
Node<T>*s = new Node<T>();
s->data = x;
rear->next = s;
rear = s;
}
template<typename T>
T LinkQueue<T>::deQueue()//链队列的删除
{
if (rear == front)
{
throw exception("删除队首结点时发生了下溢");
}
Node<T>*p = new Node<T>();
p = front->next;
T x = p->data;
front->next = p->next;
if (front->next == nullptr)
{
rear = front;
}
delete p;
return x;
}
template<typename T>
T LinkQueue<T>::getHead()
{
if (front == rear)
{
throw exception("得到队首元素时发生了下溢");
}
return front->next->data;
}
template<typename T>
bool LinkQueue<T>::empty()//判断链队列是否为空
{
if (front == rear)
{
return true;
}
return false;
}
template<typename T>
void LinkQueue<T>::printQueue()
{
if (front == rear)
{
throw exception("队列为空,无法打印队列");
}
front = front->next;
while (front != nullptr)
{
cout << front->data << endl;
front = front->next;
}
}
int main()
{
LinkQueue<int> linkQueue;
linkQueue.insertQueue(10);
linkQueue.insertQueue(100);
linkQueue.insertQueue(200);
linkQueue.insertQueue(300);
try
{
cout << "删除队首元素:" << linkQueue.deQueue() << endl;
cout << "删除队首元素:" << linkQueue.deQueue() << endl;
cout << "得到队首元素:" << linkQueue.getHead() << endl;
cout << "删除队首元素:" << linkQueue.deQueue() << endl;
cout << "删除队首元素:" << linkQueue.deQueue() << endl;
cout << linkQueue.empty() << endl;
}
catch (exception e)
{
cout << e.what() << endl;
}
return 0;
}