《STL源碼剖析》筆記:deque

概述

vector是單向開口的連續(xù)空間,deque則是雙向開口的連續(xù)空間,可以在頭尾兩端分別做元素的插入和刪除。

deque與vector最大的差異在于:

  • deque允許在常數(shù)時(shí)間內(nèi)對(duì)起頭端進(jìn)行元素的插入或者移除。
  • deque沒有容量的概念,因?yàn)樗莿?dòng)態(tài)地以分段連續(xù)空間組合而成,隨時(shí)可以增加一段新的空間并鏈接起來。亦既是在vector中那樣"因?yàn)榕f空間不足而重新分配空間,然后復(fù)制元素,再釋放舊空間"這樣的事情在deque中不會(huì)發(fā)生,因此沒有必要保留reserve等容量相關(guān)。

deque由2部分組成:

  • 緩沖區(qū):一段連續(xù)的內(nèi)存空間。
  • map:指向緩沖區(qū)的指針數(shù)組。
deque.png
template <typename T>
class Deque {
    ......
    private:
        T **_map;                      // 動(dòng)態(tài)數(shù)組
        iterator _begin;
        iterator _end;
        size_t _mapSize = 1;          // map的數(shù)量
        size_t _pageSize = 3;         // 緩沖區(qū)的大小
}

迭代器

deque是分段的連續(xù)空間,維持其"整體連續(xù)"假象的任務(wù),就落在了迭代器身上。為此迭代器必須能夠做到:

  • 能夠指向緩沖區(qū)的元素
  • 能夠判斷自己是否已處于緩沖區(qū)的邊緣。當(dāng)自己處于緩沖區(qū)的邊緣時(shí),能夠跳躍至上一個(gè)緩沖區(qū)或者下一個(gè)緩沖區(qū),需要知道自己在map中哪個(gè)位置。
    所以,在其中應(yīng)該要保留一個(gè)指向容器(其中有map)的指針,一個(gè)所處map為重的索引, 指向元素的指針。
class DequeIterator {
    private:
        Deque<T> *_containerPtr;      // 保存對(duì)容器的連接,重點(diǎn)是能訪問到map。
        T *_cur;                      // 指向緩沖區(qū)的元素
        size_t _mapIndex;             // map數(shù)組的索引,向前跳躍或者向后跳躍
};
迭代器.png
DequeIterator &operator++();
_cur = isPageTail() ? _containerPtr->_map[++_mapIndex] : ++_cur;    // 判斷是否是緩沖區(qū)末尾
return *this;
DequeIterator &operator--()
_cur = isPageHead() ? _containerPtr->_map[--_mapIndex] + (getPageSize()-1) : --_cur;  // 判斷是否是緩沖區(qū)頭部
return *this;

添加元素

void push_back(const T &value)
  • 如果沒有空間容納新元素
    • 申請(qǐng)新的map
    • 拷貝原deque的緩沖區(qū)中的元素
    • 構(gòu)造元素
if (isLastPageTail())    // 是否是Deque緩沖區(qū)的最后一個(gè)位置
    reallocateMapForTail();    
dataAlloc::construct(_end._cur, value);
++_end;
void push_front(const T& value)
if (isFirstPageHead())
    reallocateMapForHead();
--_begin;
dataAlloc::construct(_begin._cur, value);

刪除元素

void Deque<T>::pop_back()
if (empty())
    throw std::out_of_range("pop_back() on empty Deque");
--_end;
dataAlloc::destroy(_end._cur);
void pop_front()
if (empty())
    throw std::out_of_range("pop_front() on empty Deque");
dataAlloc::destroy(_begin._cur);
++_begin;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容