队列
队列是一种线性的数据结构,其特点为先入先出FIFO
注意:在C++的标准模板库(STL)中,queue
是一个容器适配器,它是基于底层容器实现的。默认情况下,queue
是通过 std::deque
来实现的,但也可以通过其他序列容器(如 std::list
)来实现
一、队列的顺序实现
1.SqQueue.h
队列可实现自动扩容,当队列中内存不足时候,以原内存的2倍大小进行扩容
队列初始化:
- 队列初始化大小为
capacity = 4
- 头指针
front= 0
,尾指针rear = 0
,初始首尾指针均可以指向同一个位置
- 队列为空:
rear == front
- 队列首部出队,首部指针后移:
front = (front + 1) % capacity
- 队列尾部入队,尾部指针后移:
rear = (rear + 1) % capacity
- 获取队列首部元素,返回:
data[front]
- 获取队列尾部部元素,返回:
data[(rear - 1 + capacity) % capacity]

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| #pragma once #include "exception"
template<typename T> class SqQueue { private: T *data; int front_,rear_, capacity; public: SqQueue(int cap = 4) { data = new T[cap]; if(data == nullptr) throw "内存分配失败";
capacity = cap; front_ = rear_ = 0; }
bool push(T e) { if((rear_ + 1) % capacity == front_) { T *p = new T[2*capacity]; if(p == nullptr) throw "内存分配失败";
for(int i = 0;i<capacity;i++) { p[i] = data[i]; } delete data; data = p; capacity *= 2; } data[rear_] = e; rear_ = (rear_ + 1) % capacity; }
bool pop() { if(front_ == rear_) return false; front_ = (front_ + 1) % capacity; return true; }
T &front() { if(front_ == rear_) throw "队列为空"; return data[front_]; }
T &rear() { if(rear_ == front_) throw "队列为空";
int pos = (rear_ - 1 + capacity) % capacity; return data[pos]; }
int size() { return (rear_ - front_ + capacity) % capacity; }
bool empty() { return front_ == rear_; }
bool clear() { front_ = rear_ = 0; } };
|
2.测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <iostream> #include "SqQeueu.h" using namespace std;
int main() { SqQueue<int> Q; bool ret = Q.push(3);
ret = Q.push(4); ret = Q.push(5); ret = Q.push(6); ret = Q.push(7); ret = Q.push(8);
int r = Q.rear(); cout << "队列尾部: " << r << endl; cout << "队列大小: " << Q.size() << endl;
while(!Q.empty()) { int f = Q.front(); Q.pop(); cout << f << " "; } cout << endl;
return 0; }
|
1 2 3
| 队列尾部: 8 队列大小: 6 3 4 5 6 7 8
|
二、队列的链式实现
链式实现,头指针指向实际的元素
尾指针指向队列的最后一个元素节点
1.LkQueue.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| #pragma once #include "exception"
template <typename T> class LkQueue{ private: struct Node{ T data; Node *next; }; Node *front_; Node *rear_;
public: LkQueue(); bool push(T e); bool pop(); T &front(); bool empty(); };
template <typename T> LkQueue<T>::LkQueue() { front_ = rear_ = new Node(); if(front_ == nullptr) throw "内存分配失败"; front_->next = nullptr; }
template <typename T> bool LkQueue<T>::push(T e) { Node *newNode = new Node; if(newNode == nullptr) return false; newNode->data = e; newNode->next = nullptr; rear_ -> next = newNode; rear_ = newNode; return true; }
template <typename T> bool LkQueue<T>::pop() { if(front_ == rear_) return false; Node *p = front_->next; front_->next = p->next; if(rear_ == p) rear_ = front_; delete p; return true; }
template <typename T> T& LkQueue<T>::front() { if(front_ == rear_) { throw "空队列"; } return front_->next->data; }
template <typename T> bool LkQueue<T>::empty() { return front_ == rear_; }
|
2.测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <iostream> #include "LkQueue.h" using namespace std;
int main() { LkQueue<int> q;
q.push(10); q.push(3); q.push(5);
cout << q.front() << endl; q.pop(); cout << q.front() << endl;
q.push(30); q.push(50);
while(!q.empty()) { cout << q.front() <<endl; q.pop(); }
return 0; }
|
三、循环队列的实现
循环队列:使用连续的内存空间存储元素
当超出下标,在回到起始下标
入队:rear = (rear + 1) % MAXSIZE
出队:front= (front+ 1) % MAXSIZE
数据元素的个数:(rear - front + MAXSIZE) % MAXSIZE

空队列:rear == front
满队列:(rear + 1) % MAXSIZE == front

1.CircleQueue.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| #pragma once #include "exception"
template <typename T> class CircleQueue{ private: T *data; int front; int rear; int capacity; public: CircleQueue(int cap); bool push(T e); bool pop(); T& Front(); T& Rear(); int Size(); bool isEmpty(); bool isFull(); void clear(); };
template <typename T> CircleQueue<T>::CircleQueue(int cap) { data = new T[cap+1]; if(data == nullptr) throw "内存分配失败"; front = rear = 0; capacity = cap+1; }
template <typename T> bool CircleQueue<T>::push(T e) { if((rear + 1) % capacity == front) { return false; }
data[rear] = e; rear = (rear + 1) % capacity; return true; }
template <typename T> bool CircleQueue<T>::pop() { if(front == rear) return false; front = (front + 1) % capacity; return true; }
template <typename T> T & CircleQueue<T>::Front() { if(front == rear) throw "队列为空";
return data[front]; }
template <typename T> T & CircleQueue<T>::Rear() { if(front == rear) throw "队列为空";
int pos = (rear - 1 + capacity) % capacity; return data[pos]; }
template <typename T> int CircleQueue<T>::Size() { int size = (rear - front + capacity) % capacity; return size; }
template <typename T> bool CircleQueue<T>::isEmpty() { if(front == rear) return true; return false; }
template <typename T> bool CircleQueue<T>::isFull() { if((rear + 1) % capacity == front) return true; return false; }
template <typename T> void CircleQueue<T>::clear() { front = rear = 0; }
|
2.测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <iostream> #include "CircleQueue.h" using namespace std;
int main() { CircleQueue<int> circleQueue(4);
cout << "队列是否为空: " << circleQueue.isEmpty() << endl;
circleQueue.push(1); circleQueue.push(2); circleQueue.push(3); circleQueue.push(4);
cout << "队列是否满: " << circleQueue.isFull() << endl; cout << "队列中元素数量: " << circleQueue.Size() << endl;
for(int i = 0;i<4;i++) { cout << "---------"<<endl; cout << "队列首部元素: " << circleQueue.Front() <<endl; cout << "队列尾部元素: " << circleQueue.Rear() << endl; cout << "队列元素数量: " << circleQueue.Size() << endl; circleQueue.pop(); }
return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 队列是否为空: 1 队列是否满: 1 队列中元素数量: 4 --------- 队列首部元素: 1 队列尾部元素: 4 队列元素数量: 4 --------- 队列首部元素: 2 队列尾部元素: 4 队列元素数量: 3 --------- 队列首部元素: 3 队列尾部元素: 4 队列元素数量: 2 --------- 队列首部元素: 4 队列尾部元素: 4 队列元素数量: 1
|
四、扩展应用
1.农夫过河问题

思路:
- 农夫带羊过河,之后单独回来
- 农夫带狼过河,之后将羊带回来
- 农夫带白菜过河,之后单独回来
- 农夫带羊过河,如此全部东西都在河的对岸了
求解:将农夫,白菜,狼,羊视作四位二进制
- 如果某个事物过河了,则其状态为1,否则围殴0,则题目变为:

