Queue

#Queue #cpp

队列

队列(Queue)是遵循先进先出(FIFO)规则的线性数据结构,正如同它的名字一样,先进入队列排队的元素会首先离开队列,像在羽毛球桶里的羽毛球一样,先放进去的球会从下面先取出来。

如图所示,删除队首元素的过程叫做出队,将新元素加入队尾的过程叫做入队。

栈的实现

STL中队列的使用

使用标准库中队列前首先应引入头文件**<queue>**,下面将简单介绍队列简单的使用。

#include <queue>
//队列的声明
std::queue<data_type> q1;
std::queue<data_type> q2;

//向队列中添加元素
q1.push(val);

//删除队首元素
q1.pop();

//复制队列
q1 = q2;

//访问队首和队尾元素
q1.front();
q1.back();

//检查队列是否为空与获取元素
q1.empty();
q1.size();

应注意的一点是,pop()没有返回值,需要先使用front()再次使用pop().

基于链表的实现

class Queue{
	private:
		Node* front;
		Node* back;
		int quesize;
	public:
		Queue(){
			front = nullptr;
			back = nullptr;
			quesize = 0;
		}
		~Queue(){
			freeMemoryNode(front);
		}
    
    	int getSize(){
            return quesize;
        }
    	
    	bool isEmpty(){
			return quesize == 0;
        }
    
    
		void push(int val){
			Node* node = new Node(val);
			if(front == nullptr){
				front = node;
				back = node;
			}
            
            else{
            	back->next = node;
				back = node;
            }
			quesize++;
		}
    	
    	void pop(){
            if(isEmpty()) throw std::runtime_error("队列为空");
            Node* tmp = front->next;
            delete front;
            front = tmp;
            quesize--;
        }
    
    	int peek(){
			if(isEmpty()) throw std::runtime_error("队列为空");
            return back->val;
        }
    	
    	
};

基于数组的实现

​ 为能专注于对队列的实现和理解,我们这里使用标准库中的**<vector>**实现。

在数组中删除元素的操作时间复杂度为$O(n)$,如果我们直接删除的话就不等于队列删除元素的操作时间复杂度$O(1)$了,所以我们这里使用frontback作为队列的首尾,每次删除只将front后移一位,而不删除元素。

#include <vector>
class Queue{
	private:
		std::vector<int> queue;
		int front;
		int back;
		int quesize;
	public:
		Queue(){
			front = -1;
			back = -1;
			quesize = 0;
		}
		~Queue(){
			//vector自动管理内存
		}
		
		int getSize(){
            return quesize;
        }
    	
    	bool isEmpty(){
			return quesize == 0;
        }
    
    
		void push(int val){
			queue.push_back(val);
			if(front == -1){
				front = 0;
				back = 0;
			}
            
            else{
            	back = queue.size()-1;
            }
			quesize++;
		}
    	
    	void pop(){
            if(isEmpty()) throw std::runtime_error("队列为空");
            front++;
            quesize--;
        }
    
    	int peek(){
			if(isEmpty()) throw std::runtime_error("队列为空");
            return queue[front];
        }
		
};

*为什么不使用C风格数组

如果不使用vector,则需要预制数组大小,并且在即将超出数组大小限制时进行扩容操作,或者将back再次指向那些被`删除`元素的下标,但这样依旧会面临扩容操作,这两种操作方式较为复杂此处不再赘述。

队列各操作效率

操作名 时间复杂度
pop() $O(1)$
push() $O(1)$
peek() $O(1)$

队列相关题目