1. 程式人生 > >從deque到std::stack,std::queue,再到iOS 中NSArray(CFArray)

從deque到std::stack,std::queue,再到iOS 中NSArray(CFArray)

blog image nis get 容器 view 緩沖 div n-1

從deque到std::stack,std::queue,再到iOS 中NSArray(CFArray)

deque

deque雙端隊列,分段連續空間數據結構,由中控的map(與其說map,不如說是數組)控制,map中每個槽指向一個固定大小的緩沖(連續的線性空間)。
deque的叠代器,關鍵的四個指針:

cur     //所指緩沖區中的現元素
first   //所指緩沖區中的頭
last    //所指緩沖區中的尾
node    //指向中控的槽

技術分享

start指向中控第一個槽位的buffer中的第一個元素,finish指向中控最後一個槽位指向的buffer中的最後一個元素。
每次新建deque時,創建中控map和nodes,根據初始的元素個數計算開始槽位nstart和nfinish。

map_pointer nstart = map + (map_size - num_nodes) / 2;
map_pointer nfinish = nstart + num_nodes - 1;

這樣做的原因是雙端push或pop時的平均性能最佳。

如圖,如果需要push_back,剛好finish指向的buffer將滿,會向map中finish後一個槽位新建一個buffer node;對應的push_front會向map中start前一個槽位新建一個buffer node;如果map不夠空間,也還是要reallocate_map,重新分配map空間遷移已有數據,釋放老數據。

std::stack,std::queue

  • stack是FILO的數據結構,只有一個出口,若以上述的deque實現,封住deque的頭端開口,輕易就能實現stack,stack往往不被歸為container,而被歸為container adapter,源碼十分簡短,底層容器就是deque(當然也可以使用list:如stack<int, list >)
class Sequence = deque<T>
  • queue是FIFO的數據結構,封住back的出口和front的入口即可輕易實現,代碼同stack,也被認為是container adapter。

NSArray(CF-1151.16源碼中的CFArray)

iOS中為什麽沒有實現stack,queue這樣的適配器?應該是CFArray底層也是類似雙端隊列這樣的數據結構,可以輕易實現FILO或FIFO功能,就沒必要再多此一舉了。
剛好在 CFArray.c 源碼中定義了__CFArrayDeque,和各種deque相關操作的方法。

struct __CFArrayDeque {
    uintptr_t _leftIdx;
    uintptr_t _capacity;
    /* struct __CFArrayBucket buckets follow here */
};

但是蘋果的NSArray真實實現誰也不知道,也可能是 環形隊列,這樣貌似性能更高,請看這篇文章;
和其他容器的實現。

小結

關於iOS為什麽不實現std::stack和std::queue,可能蘋果覺得NSMutableArray完全可以通過deque的性質輕易的實現FILO或FIFO特性,再實現就是多此一舉了吧。
ps:CF源碼我還沒看完,繼續啃吧。

參考

  • 《STL 源碼剖析》
  • http://blog.ibireme.com/2014/02/17/cfarray/
  • https://github.com/ibireme/yy_music_base/tree/master/yy_music_base

從deque到std::stack,std::queue,再到iOS 中NSArray(CFArray)