從deque到std::stack,std::queue,再到iOS 中NSArray(CFArray)
從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)