和栈相反,队列是FIFO表,先进先出。故名思议,和排队打饭一样,先入队的先打完出去,而且只能从队列的尾端加入(插队的滚粗啊。。)。用数组实现队列的话,循环队列是一般是必须的。我们会用2个下标head and tail来标记队头和队尾的位置,如果有人出队的话,head就会+1,入队tail+1,这样整个队列在数组中的位置就会慢慢向右移动,不做处理的话很快会到达数组的尾端。因此,循环队列的采取这样的操作,当队头或者队尾超出存储队列的预设长度的话,就把他们置为0,等于再从数组的左边开始向右增长,形成“卷绕”。
开始时,我们把head和tail初始化为0,这时的队列是空的,此后我们也可以用head == tail 这条语句来判断一个队列是否为空。
NOTE:采用这种判断条件的话,对于规模为N的数组来说只能规模为N - 1的队列,因为如果此时再入队一个对象,tail == head就成立了,意味着队列为空,这不符合逻辑。
判断队列满有两种情况:
1. 此时head为0,tail = length - 1,意味着已经有N - 1个对象在队列里。
2. head大于0,则队列满的条件为head = tail + 1,这种情况画个图就明白了,是由于“卷绕”造成的。
这是算法导论上的示意图。下面贴下我简单实现的代码,C++写的模板类
#ifndef _QUEUE_H_ #define _QUEUE_H_ template <class T> class Queue { private: int head; int tail; int length; T* array; public: Queue(){tail = head = length = 0;} Queue(int size); ~Queue(); bool isEmpty(); bool isFull(); void enQueue(T val); T deQueue(); }; template <class T> Queue<T>::Queue(int size) { tail = head = 0; length = size; array = new T[size]; } template <class T> Queue<T>::~Queue() { delete [] array; } template <class T> bool Queue<T>::isEmpty() { return head == tail; } template <class T> bool Queue<T>::isFull() { return (head == tail + 1) || (tail - head == length - 1); } template <class T> void Queue<T>::enQueue(T val) { if(isFull()) { std::cout << "Queue overflow!" << std::endl; /* exit or someting else */ } else { array[tail++] = val; if(tail == length) tail = 0; } } template <class T> T Queue<T>::deQueue() { T ret; if(isEmpty()) { std::cout << "Queue is empty!" << std::endl; /* exit or someting else */ } else { ret = array[head++]; if(head == length) head = 0; return ret; } } #endif
两种最基本的线性表写完了,过几天回家写个链表