隊列(Queue)
什么是隊列
隊列就是一種線性的數據結構,它與日常生活中排隊的隊列相似,即先進先出(LIFO, First In First Out),這點也是它與棧Stack的最大不同之處。它的結構類似于下面的容器:
如上圖所示,隊列的結構就像一個兩端都是開口的容器,一端只負責小球(對應隊列中的元素)進入,一個端只負責小球彈出,容器內部的小球無法跳過前面的小球提前彈出。我們將隊列的出口端(即隊列的頭部)叫做隊頭(front),入口端(即隊列的末尾)稱為隊尾(rear)。
與棧類似,隊列的底層數據結構也可以使用數組和鏈表來實現,具體如下圖所示:
隊列的基本操作和應用
隊列的基本操作與棧類似,主要是分為入隊(enqueue)和出隊(dequeue),我們以數組為例,簡單描述一下具體過程。
1. 入隊
入隊就是把新元素放入隊列中去,由于隊列的數據結構的限制,只允許將新入隊元素放入隊尾的位置,然后更新隊尾的位置,具體過程如下圖所示。
2. 出隊
出隊就是把隊列中的元素移出來,同樣的,隊列只允許在隊列的隊頭這一側移出元素,即每次移出的元素就是隊頭對應的元素,元素移出后,原對頭元素的后面一個元素變為新的隊頭,具體過程如下所示:
3. 入隊出隊的復雜度和應用
與棧類似,隊列的入隊與出隊只與隊頭和隊尾的元素相關,不涉及其他元素的移動,因此隊列的入隊和出隊的時間復雜度都是。
隊列先進先出的特性使得其常用于一下場景中:
- 消息隊列:在分布式系統或異步任務處理場景中,消息隊列可以用于解耦任務的發布與消費,確保任務能夠穩定地進行下去。
- 程序調度:操作系統、多線程程序、并發網絡程序等需要協調多個任務的程序中,通常會使用隊列來維護任務的執行順序,以保證每個任務都能夠得到執行。
- 廣度優先搜索:在圖論、路徑查找等問題中,廣度優先搜索算法通常會使用隊列來存儲待搜索的節點,以確保每一層的所有節點都可以被訪問到。
- 緩存:在許多應用中,緩存通常使用隊列來管理緩存項的過期時間和更替策略,使得緩存可以高效地使用有限的內存資源。
類模板std::queue
std::queue類是C++提供的容器適配器,它提供了特定的函數集合,實現了隊列的基本功能:FIFO的數據結構,即在容器的尾端推入元素,在首段彈出元素。std::queue類在頭文件中定義,其函數聲明如下:
template<
class T,
class Container = std::deque< T >
> class queue;
形參T和Container
- T :存儲的元素類型。
- Container :用于存儲元素的底層容器。容器類型必須是序列容器,同時,該容器類型需提供通常語義下的back()、front()、push_back()和pop_front()函數,滿足該要求的標準容器有std::deque和std::list,其中默認使用的容器是std::deque。
成員函數
1. 元素訪問
- front :訪問隊列第一個元素。其函數聲明如下:
reference front();
const_reference front() const;
該函數返回隊列中首個元素的引用,實際上該函數等效的調用的就是存儲元素的底層容器(Container)的front()函數。
- back :訪問隊列最后一個元素。其函數聲明如下:
reference back();
const_reference back() const;
該函數返回的是隊列末尾元素的引用,實際上該函數等效的調用的就是Container的back()函數。
2. 容量
- empty :檢查隊列是否為空。其函數聲明如下:
bool empty() const; // C++20 前
[[nodiscard]] bool empty() const; //C++20 起
其本質上就是檢查Container是否為空,即Container的empty()。如果為空返回true,否則為false。
- size :返回隊列中的元素個數。其函數聲明如如下:
size_type size() const;
同樣的,其本質還是返回的是Container的元素個數,即Container的size()。
3. 隊列的修改
- push :向隊列的尾部插入元素,對應的就是入隊操作。其函數聲明如下:
void push( const value_type& value );
void push( value_type&& value ); //C++11 起
- emplace :在隊列的尾部構造元素,對應的也是入隊的操作。其函數聲明如下:
template< class... Args >
void emplace( Args&&... args );// C++11 起 C++17 前
template< class... Args >
decltype(auto) emplace( Args&&... args );// C++17 起
該函數就是將新元素推到隊列的尾部,其與push不同的是:該函數是原地構造元素,即不進行移動或復制操作,使用參數直接原地調用元素的構造函數,使得其效率高于push。
- pop :刪除隊列首個元素,對應的就是出隊操作。其函數聲明如下:
void pop();
該函數移除隊列前端的元素,等效的調用了Container的pop_front()函數。
- swap :交換兩個容器的內容。其函數聲明如下:
void swap( queue& other ) noexcept(); //C++11 起
其本質上是交換兩個Container中的內容。
用法示例
#include < iostream >
#include < queue >
using namespace std;
void showQueue(string queueName, queue< int >& q) {
cout < < "隊列" < < queueName < < "中元素的數量, 即size() = " < < q.size()
< < endl;
if (!q.empty()) {
cout < < "此時, 隊列" < < queueName < < "不為空,即empty() = false" < < endl;
cout < < "隊列首位元素,即front() = " < < q.front() < < endl;
cout < < "隊列首位元素,即back() = " < < q.back() < < endl;
} else {
cout < < "此時, 隊列" < < queueName < < "為空,即empty() = true" < < endl;
}
}
int main() {
queue< int > q;
// push()
q.push(1);
q.push(2);
q.push(3);
cout < < "---按順push元素1、2、3后:n" < < endl;
showQueue("q", q);
q.pop(); // 彈出隊頭元素
cout < < "n---彈出隊頭元素3, 即pop()后:n" < < endl;
showQueue("q", q);
q.pop();
cout < < "n---彈出隊頭元素2, 即pop()后:n" < < endl;
showQueue("q", q);
q.pop();
cout < < "n---彈出隊頭元素1, 即pop()后:n" < < endl;
showQueue("q", q);
queue< int > q1;
q1.emplace(1);
q1.emplace(2);
q1.emplace(3);
cout < < "n-----------隊列q和q1交換前----------" < < endl;
cout < < "nq的狀態: " < < endl;
showQueue("q", q);
cout < < "nq1的狀態: " < < endl;
showQueue("q1", q1);
q1.swap(q); // s和s1進行交換
cout < < "n-----------隊列q和q1交換后----------n" < < endl;
showQueue("q", q);
cout < < "nq1的狀態: " < < endl;
showQueue("q1", q1);
return 0;
}
輸出結果:
---按順push元素1、2、3后:
隊列q中元素的數量, 即size() = 3
此時, 隊列q不為空,即empty() = false
隊列首位元素,即front() = 1
隊列首位元素,即back() = 3
---彈出隊頭元素3, 即pop()后:
隊列q中元素的數量, 即size() = 2
此時, 隊列q不為空,即empty() = false
隊列首位元素,即front() = 2
隊列首位元素,即back() = 3
---彈出隊頭元素2, 即pop()后:
隊列q中元素的數量, 即size() = 1
此時, 隊列q不為空,即empty() = false
隊列首位元素,即front() = 3
隊列首位元素,即back() = 3
---彈出隊頭元素1, 即pop()后:
隊列q中元素的數量, 即size() = 0
此時, 隊列q為空,即empty() = true
-----------隊列q和q1交換前----------
q的狀態:
隊列q中元素的數量, 即size() = 0
此時, 隊列q為空,即empty() = true
q1的狀態:
隊列q1中元素的數量, 即size() = 3
此時, 隊列q1不為空,即empty() = false
隊列首位元素,即front() = 1
隊列首位元素,即back() = 3
-----------隊列q和q1交換后----------
隊列q中元素的數量, 即size() = 3
此時, 隊列q不為空,即empty() = false
隊列首位元素,即front() = 1
隊列首位元素,即back() = 3
q1的狀態:
隊列q1中元素的數量, 即size() = 0
此時, 隊列q1為空,即empty() = true
-
適配器
+關注
關注
8文章
1952瀏覽量
68024 -
緩存器
+關注
關注
0文章
63瀏覽量
11659 -
C++語言
+關注
關注
0文章
147瀏覽量
6992 -
FIFO存儲
+關注
關注
0文章
103瀏覽量
5973
發布評論請先 登錄
相關推薦
評論