队列是一种先入先出的数据结构,队列可以看作日常的排队,先到的现办理业务。
队列的常规操作:push/pop/front/back/empty/size
queue<int> queue;
queue.push(1);//入列
queue.push(3);
queue.push(5);
queue.push(7);
//此时队列为 1 3 5 7
cout<<queue.front()<<endl;//队首元素访问
queue.pop();//队首元素出列
cout<<queue.back()<<endl;//队尾元素访问
bool Empty=queue.empty();//队列是否为空
单项队列实现
队列实现必须具备一端加入元素,另一端删除元素的特征,数组和链表都具备这样的特性。
1.基于数组实现
由于数组删除首元素的时间复杂度是O(n),所以导致出队效率比较低,可以采用以下方式避免这个问题。
使用front指向队首元素的索引,使用size维护队列长度,定义rear=front+size,即rear是队尾元素的下一个位置索引。此时队列的有效元素全部在数组的有效区间[front, rear-1]内。
入队: 元素赋值到索引为rear处,size加1;
出队: front往下移动一位,即front++,同时size--;
此时,无论入队还是出队时间复杂度都是O(n)。
此时发现,无论是入队还是出队,front和rear都在往后移动,当达到数组尾部就无法移动了!因此使用环形数组(让front或rear越过数组尾部时,从头继续遍历)可以解决这个问题。
//基于数组实现的队列
class ArrayQueue{
private:
int *nums;
int queSize;
int front;
int queCapacity;
public:
//构造函数初始化队列
ArrayQueue(int capacity){
front=queSize=0;
nums= new int[capacity];
queCapacity=capacity;
}
~ArrayQueue(){
delete []nums;
}
//获取队列容量
int capacity(){
return queCapacity;
}
//获取队列长度
int size(){
return queSize;
}
//判断队列是否为空
bool empty(){
return size()==0;
}
//入队操作
void push(int num){
if(queSize==queCapacity){
cout<<"队列已满"<<endl;
return ;
}
int rear=(front+queSize)%queCapacity;//通过取余使得rear越过数组尾端,继续从头遍历
nums[queSize]=num;
queSize++;
}
//出队操作
int pop(){
int num=peek();
// 队首指针向后移动一位,若越过尾部,则返回到数组头部
front=(front+1)%queCapacity;
queSize--;
return num;
}
//访问队列首元素
int peek(){
if (empty()) throw out_of_range(" 队列为空");
return nums[front];
}
//将数组转换为Vector并返回
vector<int> toVector(){
//仅转换为有效长度范围内的列表元素
vector<int> arr(queSize);
for(int i =0, j=front;i<queSize;i++,j++){
arr[i]=nums[j%queCapacity];
}
return arr;
}
};
2.基于链表实现的队列
可以将链表的头节点和尾节点分别看作“队首”和“队尾”。并规定队首仅可以删除节点,队尾尽可以添加节点。
class LinkedListQueue{
private:
ListNode *front,*rear;//头节点,尾节点
int queSize;
public:
LinkedListQueue(){
front =nullptr;
rear=nullptr;
queSize=0;
}
~LinkedListQueue(){
//遍历链表删除节点,释放内存
freeMemoryLinkedList(front);
}
//获取队列长度
int size(){
return queSize;
}
//判断队列是否为空
bool isEmpty(){
return size()==0;
}
//入队操作
void push(int num){
//在尾节点后添加num
ListNode *node=new ListNode(num);
//若队列为空,说明添加的这个节点是唯一节点,头节点和尾节点都指向它
if(front==nullptr){
front = node;
rear = node;
}
else{
rear->next=node;
rear = node;
}
queSize++;
}
//出队操作
int pop(){
int num=peek();//用于出队时,返回到底出队的元素是什么
ListNode* tmp = fornt;
front = front->next;
//释放内存
delete tmp;
queSize--;
return num;
}
//访问队首元素
int peek(){
if(size()==0){
throw out_of_range("队列是空的");
}
return front->val;
}
//将链表转换为vector并返回
vector<int> toVector(){
ListNode* node =front;
vector<int> ans(size());
for( int i =0;i<ans.size();i++){
ans[i]=node->val;
node=node->next;
}
return ans;
}
};
声明:本人所写内容全部参考hello-algo,仅用于个人复习。