生活随笔
收集整理的這篇文章主要介紹了
C++中的deque、stack、queue及priority_queue
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
C++中的deque、stack、queue及priority_queue
文章目錄
- C++中的deque、stack、queue及priority_queue
- 一、deque
- 二、stack
- 三、queue
- 四、priority_queue
- 五、相關(guān)注意事項
一、deque
deque(發(fā)音類似“deck”),是雙端隊列不規(guī)則的首字母縮寫,雙端隊列是動態(tài)大小的序列式容器,其可以像兩端進(jìn)行伸縮。特定的庫可以以不同的方式實(shí)現(xiàn)deque,但通常都是一種動態(tài)數(shù)組。不論在何種情況下,它都允許通過隨機(jī)訪問迭代器直接訪問單個元素,可以根據(jù)需要動態(tài)的伸縮。因此,deque提供了一些與vector相似的功能,但deque在頭部和尾部進(jìn)行數(shù)據(jù)插入和刪除操作更加高效。與vector不同的是,deque不能保證所有的元素存儲在連續(xù)的空間中,在deque中通過指針加偏移量方式訪問元素可能會導(dǎo)致非法的操作。vector與list提供了相似的接口,因此其具有類似的用途,但是內(nèi)部的實(shí)現(xiàn)原理不同:vector使用使用了動態(tài)數(shù)組,該數(shù)組通常需要動態(tài)增長;deque中的元素可能分散在不同的存儲塊中在deque中保存了一些必要的信息,通常用來在常數(shù)范圍內(nèi)直接訪問deque中的任何一個元素,所以deque的內(nèi)部實(shí)現(xiàn)比vector復(fù)雜,但是這些額外信息使得dque在某些情況下增長更加的高效,特別是在序列比較大,重新分配成本比較高的情況下。除了在頻繁在頭部或尾部進(jìn)行插入和刪除操作外,deque比list和forward_list的性能更差
- 3 .deque的應(yīng)用場景
- deque在序列式容器中比較雞肋,因為如果只是簡單的存儲元素,使用vector即可
- 如果對元素任意位置進(jìn)行插入或者刪除操作比較多,使用list即可
- 所以一般很少去使用deque。deque最大的應(yīng)用,就是用其作為標(biāo)準(zhǔn)庫中stack和queue的底層結(jié)構(gòu)
二、stack
stack是一種容器適配器,專門用在具有后進(jìn)先出操作的上下文環(huán)境中,其刪除只能從容器的一端進(jìn)行元素的插入與提取操作。stack是作為容器適配器被實(shí)現(xiàn)的,容器適配器即是對特定類封裝作為其底層的容器,并提供一組特定的成員函數(shù)來訪問其元素,將特定類作為其底層的,元素特定容器的尾部(即棧頂)被壓入和彈出。stack的底層容器可以是任何標(biāo)準(zhǔn)的容器類模板或者一些其他特定的容器類,這些容器類應(yīng)該支持以下操作:
empty:判空操作
back:獲取尾部元素操作
push_back:尾部插入元素操作
pop_back:尾部刪除元素操作
標(biāo)準(zhǔn)容器vector、deque、list均符合這些需求,默認(rèn)情況下,如果沒有為stack指定特定的底層容器,默認(rèn)情況下使用deque。
#include<deque>namespace wolf
{template<class T, class Con = deque
<T
>>class stack{public:stack() {}void push(const T
& x
) {_c
.push_back(x
);}void pop() {_c
.pop_back();}T
& top() {return _c
.back();}const T
& top()const {return _c
.back();}size_t
size()const {return _c
.size();}bool empty()const {return _c
.empty();}private:Con _c
;};
}
三、queue
隊列是一種容器適配器,專門用于在FIFO上下文(先進(jìn)先出)中操作,其中從容器一端插入元素,另一端提取元素。隊列作為容器適配器實(shí)現(xiàn),容器適配器即將特定容器類封裝作為其底層容器類,queue提供一組特定的成員函數(shù)來訪問其元素。元素從隊尾入隊列,從隊頭出隊列。底層容器可以是標(biāo)準(zhǔn)容器類模板之一,也可以是其他專門設(shè)計的容器類。該底層容器應(yīng)至少支持以下操作:
empty:檢測隊列是否為空
size:返回隊列中有效元素的個數(shù)
front:返回隊頭元素的引用
back:返回隊尾元素的引用
push_back:在隊列尾部入隊列
pop_front:在隊列頭部出隊列
標(biāo)準(zhǔn)容器類deque和list滿足了這些要求。默認(rèn)情況下,如果沒有為queue實(shí)例化指定容器類,則使用標(biāo)準(zhǔn)容器deque
#include<deque>namespace wolf
{template<class T, class Con = deque
<T
>>class queue{public:queue() {}void push(const T
& x
) {_c
.push_back(x
);}void pop() {_c
.pop_front();}T
& back() {return _c
.back();}const T
& back()const {return _c
.back();}T
& front() {return _c
.front();}const T
& front()const {return _c
.front();}size_t
size()const {return _c
.size();}bool empty()const {return _c
.empty();}private:Con _c
;};
}
四、priority_queue
優(yōu)先隊列是一種容器適配器,根據(jù)嚴(yán)格的弱排序標(biāo)準(zhǔn),它的第一個元素總是它所包含的元素中最大的。此上下文類似于堆,在堆中可以隨時插入元素,并且只能檢索最大堆元素(優(yōu)先隊列中位于頂部的元素)。優(yōu)先隊列被實(shí)現(xiàn)為容器適配器,容器適配器即將特定容器類封裝作為其底層容器類,queue提供一組特定的成員函數(shù)來訪問其元素。元素從特定容器的“尾部”彈出,其稱為優(yōu)先隊列的頂部。底層容器可以是任何標(biāo)準(zhǔn)容器類模板,也可以是其他特定設(shè)計的容器類。容器應(yīng)該可以通過隨機(jī)訪問迭代器訪問,并支持以下操作:
empty():檢測容器是否為空
size():返回容器中有效元素個數(shù)
front():返回容器中第一個元素的引用
push_back():在容器尾部插入元素
pop_back():刪除容器尾部元素
- 標(biāo)準(zhǔn)容器類vector和deque滿足這些需求。默認(rèn)情況下,如果沒有為特定的priority_queue類實(shí)例化指定容器類,則使用vector。
- 需要支持隨機(jī)訪問迭代器,以便始終在內(nèi)部保持堆結(jié)構(gòu)。容器適配器通過在需要時自動調(diào)用算法函數(shù)make_heap、push_heap和pop_heap來自動完成此操作
- 2.priority_queue的使用
- 優(yōu)先級隊列默認(rèn)使用vector作為其底層存儲數(shù)據(jù)的容器,在vector上又使用了堆算法將vector中元素構(gòu)造成堆的結(jié)構(gòu),因此priority_queue就是堆
- 所有需要用到堆的位置,都可以考慮使用priority_queue。注意:默認(rèn)情況下priority_queue是大堆
處理內(nèi)置類型的情況:
#include <vector>
#include <queue>
#include <functional> void TestPriorityQueue()
{vector
<int> v
{3,2,7,6,0,4,1,9,8,5};priority_queue
<int> q1
;for (auto& e
: v
)q1
.push(e
);cout
<< q1
.top() << endl
;priority_queue
<int, vector
<int>, greater
<int>> q2(v
.begin(), v
.end());cout
<< q2
.top() << endl
;
}
- 如果在priority_queue中放自定義類型的數(shù)據(jù),用戶需要在自定義類型中提供> 或者< 的重載
class Date
{
public:Date(int year
= 1900, int month
= 1, int day
= 1): _year(year
), _month(month
), _day(day
){}bool operator<(const Date
& d
)const{return (_year
< d
._year
) ||(_year
== d
._year
&& _month
< d
._month
) ||(_year
== d
._year
&& _month
== d
._month
&& _day
< d
._day
);}bool operator>(const Date
& d
)const{return (_year
> d
._year
) ||(_year
== d
._year
&& _month
> d
._month
) ||(_year
== d
._year
&& _month
== d
._month
&& _day
> d
._day
);}friend ostream
& operator<<(ostream
& _cout
, const Date
& d
){_cout
<< d
._year
<< "-" << d
._month
<< "-" << d
._day
;return _cout
;}
private:int _year
;int _month
;int _day
;
};void TestPriorityQueue()
{priority_queue
<Date
> q1
;q1
.push(Date(2018, 10, 29));q1
.push(Date(2018, 10, 28));q1
.push(Date(2018, 10, 30));cout
<< q1
.top() << endl
;priority_queue
<Date
, vector
<Date
>, greater
<Date
>> q2
;q2
.push(Date(2018, 10, 29));q2
.push(Date(2018, 10, 28));q2
.push(Date(2018, 10, 30));cout
<< q2
.top() << endl
;
}
class Less
{
public:bool operator()(const Date
* pLeft
, const Date
* pRight
){return *pLeft
< *pRight
;}
};void TestPriorityQueue()
{priority_queue
<Date
*, vector
<Date
*>, Less
> q
;q
.push(&Date(2018, 10, 29));q
.push(&Date(2018, 10, 28));q
.push(&Date(2018, 10, 30));cout
<< *q
.top() << endl
;return 0;
}
- priority_queue的模擬實(shí)現(xiàn)
namespace wolf
{template <class T, class Sequence = vector
<T
>, class Compare = less
<T
> >class priority_queue{public:priority_queue() : c(){}template <class InputIterator>priority_queue(InputIterator first
, InputIterator last
): c(first
, last
){make_heap(c
.begin(), c
.end(), comp
);}bool empty() const { return c
.empty(); }size_t
size() const { return c
.size(); }T
& top() const { return c
.front(); }void push(const T
& x
){c
.push_back(x
);push_heap(c
.begin(), c
.end(), comp
);}void pop(){pop_heap(c
.begin(), c
.end(), comp
);c
.pop_back();}private: Sequence c
;Compare comp
;};}
五、相關(guān)注意事項
-
1.為什么使用deque作為stack和queue的底層結(jié)構(gòu)?
-
首先deque的優(yōu)點(diǎn)是頭部和尾部操作方便,效率可以達(dá)到O(1),缺點(diǎn)是因為deque的底層空間是不連續(xù)的,之所以看起來是連續(xù)的都是迭代器的功勞
-
正是因為deque的空間不連續(xù),所以對其遍歷的效率極低,因為要判斷尋找下一段空間的位置。
-
而stack和queue是作為容器適配器來使用的,其不需要遍歷,只需要在兩端進(jìn)行操作即可,剛好避開deque的缺陷。
-
雖然其他容器也可以作為stack和queue的底層結(jié)構(gòu),但效率都沒有deque高
-
2.什么是容器適配器?
-
適配器是一種設(shè)計模式(設(shè)計模式是一套被反復(fù)使用的、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗的總 結(jié)),該中模式是將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口
-
3.為什么將stack、queue和priority_queue稱作為容器適配器?
-
雖然stack、queue、priority_queue中也可以存放元素,但在STL中并沒有將其劃分在容器的行列,而是將其稱為容器適配器,這是因為每個容器在底層都有自己的實(shí)現(xiàn)方式,而stack、queue、priority_queue只是在底層將其他容器進(jìn)行了封裝
總結(jié)
以上是生活随笔為你收集整理的C++中的deque、stack、queue及priority_queue的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。