1 概述
- 先进先出(FIFO)的线性表
- 队尾:插入元素;队首:删除元素
- 抽象数据类型:queue ADT
C++代码实现:
template<class T>
class queue
{
public:
virtual ~queue() {}
virtual bool empty() const = 0;
// return true iff queue is empty
virtual int size() const = 0;
// return number of elements in queue
virtual T& front() = 0;
// return reference to the front element
virtual T& back() = 0;
// return reference to the back element
virtual void pop() = 0;
// remove the front element
virtual void push(const T& theElement) = 0;
// add theElement at the back of the queue
};
2 数组描述
2.1 数组和队列的映射
- 方案一:采用公式
l
o
c
a
t
i
o
n
(
i
)
=
i
location(i)=i
location(i)=i
queue[i]为队列中第i个元素,arrayLength是队列的长度,queueFront和queueBack分别为队首和队尾元素位置,则有: q u e u e F r o n t = 0 queueFront=0 queueFront=0 q u e u e B a c k = a r r a y L e n g t h − 1 queueBack=arrayLength-1 queueBack=arrayLength−1
特别地,当队列为空时: q u e u e B a c k = − 1 queueBack=-1 queueBack=−1
插入元素:queueBack++,queue[queueBack]=theElement。
删除元素:queue[1: queueBack]整体左移一个位置(时间复杂度线性) - 方案二:采用公式
l
o
c
a
t
i
o
n
(
i
)
=
l
o
c
a
t
i
o
n
(
队
首
元
素
)
+
i
location(i)=location(队首元素)+i
location(i)=location(队首元素)+i
按照上述公式,则有: q u e u e F r o n t = l o c a t i o n ( 队 首 元 素 ) queueFront=location(队首元素) queueFront=location(队首元素) q u e u e B a c k = l o c a t i o n ( 队 尾 元 素 ) queueBack=location(队尾元素) queueBack=location(队尾元素)
特别地,当队列为空时: q u e u e B a c k < q u e u e F r o n t queueBack<queueFront queueBack<queueFront
在最坏的情况下想要插入元素,仍然不能避免队列整体向左平移,从而降低了插入效率。 - 方案三:采用公式
l
o
c
a
t
i
o
n
(
i
)
=
(
l
o
c
a
t
i
o
n
(
队
首
元
素
)
+
i
)
%
a
r
r
a
y
L
e
n
g
t
h
location(i)=(location(队首元素)+i)\%arrayLength
location(i)=(location(队首元素)+i)%arrayLength
将数组视为一个环,arrayLength-1的下一个是0,0的前一个是arrayLength-1。
在这种情况下,当且仅当 q u e u e F r o n t = q u e u e B a c k queueFront=queueBack queueFront=queueBack时,队列为空,然而queue元素个数等于数组长度时, q u e u e F r o n t = q u e u e B a c k queueFront=queueBack queueFront=queueBack也成立,解决办法是:队列不能插满,队列元素个数最多是arrayLength-1。
2.2 C++语言实现
arrayQueue类声明:
class arrayQueue : public queue<T>
{
public:
arrayQueue(int initialCapacity = 10);
~arrayQueue() { delete[] queue; }
bool empty() const { return theFront == theBack; }
int size() const
{
return (theBack - theFront + arrayLength) % arrayLength;
}
T& front()
{// return front element
if (theFront == theBack)
throw queueEmpty();
return queue[(theFront + 1) % arrayLength];
}
T& back()
{// return theBack element
if (theFront == theBack)
throw queueEmpty();
return queue[theBack];
}
void pop()
{// remove theFront element
if (theFront == theBack)
throw queueEmpty();
theFront = (theFront + 1) % arrayLength;
queue[theFront].~T(); // destructor for T
}
void push(const T & theElement);
private:
int theFront; // 1 counterclockwise from theFront element
int theBack; // position of theBack element
int arrayLength; // queue capacity
T * queue; // element array
};
push方法实现:
template<class T>
void arrayQueue<T>::push(const T & theElement)
{// Add theElement to queue.
// increase array length if necessary
if ((theBack + 1) % arrayLength == theFront)
{// double array length
// allocate a new array
T* newQueue = new T[2 * arrayLength];
// copy elements into new array
int start = (theFront + 1) % arrayLength;
if (start < 2)
// no wrap around
copy(queue + start, queue + start + arrayLength - 1, newQueue);
else
{ // queue wraps around
copy(queue + start, queue + arrayLength, newQueue);
copy(queue, queue + theBack + 1, newQueue + arrayLength - start);
}
// switch to newQueue and set theFront and theBack
theFront = 2 * arrayLength - 1;
theBack = arrayLength - 2; // queue size arrayLength - 1
arrayLength *= 2;
queue = newQueue;
}
// put theElement at the theBack of the queue
theBack = (theBack + 1) % arrayLength;
queue[theBack] = theElement;
}
3 链表描述
从头到尾和从尾到头
对比:插入操作
插入操作均适用。
对比:删除操作
从头至尾的链接方向更适合删除操作。
给出从头至尾链接的插入和删除操作实现代码:
template<class T>
void linkedQueue<T>::pop()
{// Delete front element.
if (queueFront == NULL)
throw queueEmpty();
chainNode<T> * nextNode = queueFront->next;
delete queueFront;
queueFront = nextNode;
queueSize--;
}
template<class T>
void linkedQueue<T>::push(const T & theElement)
{// Add theElement to back of queue.
// create node for new element
chainNode<T>* newNode = new chainNode<T>(theElement, NULL);
// add new node to back of queue
if (queueSize == 0)
queueFront = newNode; // queue empty
else
queueBack->next = newNode; // queue not empty
queueBack = newNode;
queueSize++;
}
4 应用
列车车厢重排
电路布线
图元识别
工厂仿真