• C++ -- 学习系列 std::deque 的原理与使用


    一   deque 是什么?

    std::deque 是 c++ 一种序列式容器,其与 vector 类似,其底层内存都是连续的,不同的地方在于, vector 是一端开口,在一端放入数据与扩充空间,而 deque 是双端均开口,都可以放入数据与扩充空间。

    二  原理

    deque中存在两种数组:中控数组与缓存数组,在 deque 初始化时,两种数组均会初始化完成。

    1. 缓存数组有多个,缓存数组用于存储真正的元素

    2.中控数组用于存放缓存数组的地址,方便快速定位到指定缓存数组,进而快速定位元素的位置

    其原理图如下:

    其迭代器 Iterator 中需要含有四种信息:

    1. 当前元素所在缓存数组的首元素地址

    2. 当前元素所在缓存数组的尾元素地址

    3. 当前元素在缓存数组中的实际地址

    4. 当前元素所在缓存数组在中控数组的地址

    三  使用

    1. 容器构造

    std::deque::deque - cppreference.com

    函数说明
    deque( size_type count,

                    const T& value,

                    const Allocator& alloc = Allocator() );
    定义 count 个值为 value的元素存储到 deque 中             
    deque( std::initializer_list init,
           const Allocator& alloc = Allocator() );
    通过 list 定义 deque 
    1. #include
    2. #include
    3. template<typename T>
    4. void printDeque(std::deque& tmp_deque)
    5. {
    6. for(auto iter = tmp_deque.begin(); iter != tmp_deque.end(); iter++)
    7. {
    8. std::cout << *iter <<" ";
    9. }
    10. std::cout <<"" << std::endl;
    11. }
    12. int main()
    13. {
    14. std::deque<int> tmp_deque1(6, 8);
    15. printDeque(tmp_deque1);
    16. std::deque<int> tmp_deque2;
    17. tmp_deque2 = {1, 2 , 3, 4, 5, 6};
    18. printDeque(tmp_deque2);
    19. return 0;
    20. }

    2. 访问元素

    https://en.cppreference.com/w/cpp/container/deque

    函数说明
    at返回指定下标元素的引用
    operator[]同上
    front返回容器的首元素引用
    back返回容器的尾元素引用
    1. #include
    2. #include
    3. int main()
    4. {
    5. std::deque<int> tmp_deque2 = {1, 2 , 3, 4, 5, 6};
    6. // Read Element
    7. std::cout << tmp_deque2.at(1) << std::endl;
    8. std::cout << tmp_deque2[2] << std::endl;
    9. std::cout << tmp_deque2.front() << std::endl;
    10. std::cout << tmp_deque2.back() << std::endl;
    11. // Wirte Element
    12. tmp_deque2.at(1) = 888;
    13. tmp_deque2[2] = 888;
    14. tmp_deque2.front() = 888;
    15. tmp_deque2.back() = 888;
    16. std::cout << tmp_deque2.at(1) << std::endl;
    17. std::cout << tmp_deque2[2] << std::endl;
    18. std::cout << tmp_deque2.front() << std::endl;
    19. std::cout << tmp_deque2.back() << std::endl;
    20. return 0;
    21. }

    3. 容器空间

    函数说明
    empty()返回 deque 是否为空
    size()返回 deque 实际存储元素的个数
    1. #include
    2. #include
    3. int main()
    4. {
    5. std::deque<int> tmp_deque2;
    6. tmp_deque2 = {1, 2 , 3, 4, 5, 6};
    7. std::deque<int> tmp_deque3;
    8. std::cout << tmp_deque3.empty() << std::endl;
    9. std::cout << tmp_deque3.size() << std::endl;
    10. std::cout << tmp_deque2.empty() << std::endl;
    11. std::cout << tmp_deque2.size() << std::endl;
    12. return 0;
    13. }

    4. 容器修改

    std::deque - cppreference.com

    函数说明
    clear()清空 deque 的内容
    push_backappend 元素到 deque 的尾端
    pop_back将 deque 的尾端元素弹出
    push_frontappend 元素到 deque 的前端
    pop_front将 deque 的前端元素弹出
    1. #include
    2. #include
    3. template<typename T>
    4. void printDeque(std::deque& tmp_deque)
    5. {
    6. for(auto iter = tmp_deque.begin(); iter != tmp_deque.end(); iter++)
    7. {
    8. std::cout << *iter <<" ";
    9. }
    10. std::cout <<"" << std::endl;
    11. }
    12. int main(0
    13. {
    14. std::deque<int> tmp_deque2;
    15. tmp_deque2 = {1, 2 , 3, 4, 5, 6};
    16. printDeque(tmp_deque2);
    17. tmp_deque2.push_back(22);
    18. tmp_deque2.push_front(33);
    19. std::cout << tmp_deque2.front() << std::endl;
    20. std::cout << tmp_deque2.back() << std::endl;
    21. printDeque(tmp_deque2);
    22. tmp_deque2.pop_back();
    23. tmp_deque2.pop_front();
    24. std::cout << tmp_deque2.front() << std::endl;
    25. std::cout << tmp_deque2.back() << std::endl;
    26. printDeque(tmp_deque2);
    27. tmp_deque2.clear();
    28. std::cout << tmp_deque2.empty() << std::endl;
    29. return 0;
    30. }

    四  简单实现

       1. 参照原理做了简单的实现,实现了几个简单的函数接口:

      

    1. // my_deque.h
    2. #ifndef MY_DEQUE_H
    3. #define MY_DEQUE_H
    4. #include
    5. #include
    6. // 迭代器, T 为 my_deque 的元素类型, buffserSize 为每个缓存区的大小
    7. template<typename T, int bufferSize>
    8. struct my_deque_iterator
    9. {
    10. T* M_start; // 当前buffer 的起始位置
    11. T* M_finish; // 当前buffer 的结尾位置
    12. T* M_curr; // 当前元素的位置
    13. T** M_map_node; // 当前 buffer 对应的中控数组的位置
    14. my_deque_iterator(T* start = nullptr, T* finish = nullptr, T* curr = nullptr, T** map_node = nullptr):
    15. M_start(start), M_finish(finish), M_curr(curr),M_map_node(map_node)
    16. {
    17. }
    18. my_deque_iterator(const my_deque_iterator& other):M_start(other.M_start), M_finish(other.M_finish), M_curr(other.M_curr),M_map_node(other.M_map_node)
    19. {
    20. }
    21. my_deque_iterator(my_deque_iterator& other):M_start(other.M_start), M_finish(other.M_finish), M_curr(other.M_curr),M_map_node(other.M_map_node)
    22. {
    23. }
    24. my_deque_iterator& operator++()
    25. {
    26. if(M_curr == M_finish)
    27. {
    28. M_map_node += 1;
    29. set_M_Node(M_map_node);
    30. }
    31. else
    32. {
    33. M_curr++;
    34. }
    35. return *this;
    36. }
    37. my_deque_iterator& operator++(int)
    38. {
    39. my_deque_iterator tmp = *this;
    40. ++*this;
    41. return tmp;
    42. }
    43. my_deque_iterator& operator--()
    44. {
    45. if(M_curr == M_start)
    46. {
    47. M_map_node -= 1;
    48. set_M_Node(M_map_node, bufferSize - 1);
    49. }
    50. else
    51. {
    52. M_curr--;
    53. }
    54. return *this;
    55. }
    56. my_deque_iterator& operator--(int)
    57. {
    58. my_deque_iterator tmp = *this;
    59. --*this;
    60. return tmp;
    61. }
    62. T& operator*()
    63. {
    64. return *(this->M_curr);
    65. }
    66. my_deque_iterator& operator+=(int offset)
    67. {
    68. if(offset >=0 && M_curr + offset <= M_finish || offset < 0 && M_curr + offset >= M_start)
    69. {
    70. M_curr += offset;
    71. }
    72. else
    73. {
    74. int diff = offset >= 0 ? M_finish - M_curr + 1 : M_curr - M_start + 1;
    75. int offsetNode = offset >= 0 ? (offset - diff) / bufferSize + 1
    76. : ((offset + diff) / bufferSize - 1);
    77. int offsetBuff = offset >= 0 ? (offset - diff) % bufferSize :
    78. (diff + offset) % bufferSize;
    79. M_map_node += offsetNode;
    80. if(offset >= 0)
    81. {
    82. set_M_Node(M_map_node, offsetBuff);
    83. }
    84. else
    85. {
    86. set_M_Node(M_map_node, bufferSize - 1 - offsetBuff);
    87. }
    88. }
    89. return *this;
    90. }
    91. my_deque_iterator& operator-=(int offset)
    92. {
    93. this->operator+=(-offset);
    94. return *this;
    95. }
    96. my_deque_iterator operator+(int offset)
    97. {
    98. my_deque_iterator tmp = *this;
    99. tmp += offset;
    100. return tmp;
    101. }
    102. my_deque_iterator& operator-(int offset)
    103. {
    104. this->operator-=(offset);
    105. return *this;
    106. }
    107. void set_M_Node(T** map_node, int offset = 0)
    108. {
    109. M_start = M_map_node[0];
    110. M_curr = M_start + offset;
    111. M_finish = M_start + bufferSize - 1;
    112. }
    113. bool operator==(my_deque_iterator& other)
    114. {
    115. return this->M_curr == other.M_curr;
    116. }
    117. bool operator!=(my_deque_iterator& other)
    118. {
    119. return this->M_curr != other.M_curr;
    120. }
    121. bool operator==(my_deque_iterator&& other)
    122. {
    123. return this->M_curr == other.M_curr;
    124. }
    125. bool operator!=(my_deque_iterator&& other)
    126. {
    127. return this->M_curr != other.M_curr;
    128. }
    129. my_deque_iterator& operator=(my_deque_iterator& other)
    130. {
    131. this->M_start = other.M_start;
    132. this->M_curr = other.M_curr;
    133. this->M_finish = other.M_finish;
    134. this->M_map_node = other.M_map_node;
    135. return *this;
    136. }
    137. my_deque_iterator& operator=(my_deque_iterator&& other)
    138. {
    139. this->M_start = other.M_start;
    140. this->M_curr = other.M_curr;
    141. this->M_finish = other.M_finish;
    142. this->M_map_node = other.M_map_node;
    143. return *this;
    144. }
    145. };
    146. template<typename T, int bufferSize>
    147. class my_deque
    148. {
    149. public:
    150. typedef my_deque_iterator Iterator;
    151. public:
    152. my_deque(int map_size = 9):M_map_size(map_size){
    153. M_map = new T*[M_map_size];
    154. for(int i = 0; i < M_map_size; i++)
    155. {
    156. M_map[i] = new T[bufferSize];
    157. for(int j = 0; j < bufferSize; j++)
    158. {
    159. M_map[i][j] = 0;
    160. }
    161. }
    162. }
    163. ~my_deque()
    164. {
    165. for(int i = 0; i < M_map_size; i++)
    166. {
    167. delete [] M_map[i];
    168. }
    169. delete [] M_map;
    170. }
    171. void push_front(T& val){
    172. // 元素存储到了起始位置
    173. if(M_start.M_curr == &M_map[0][0])
    174. {
    175. reAlloc(M_map_size * 2);
    176. }
    177. if(M_start.M_curr == nullptr)
    178. {
    179. M_map[M_map_size/2][0] = val;
    180. M_start = Iterator(&M_map[M_map_size/2][0], &M_map[M_map_size/2][0] + bufferSize - 1, &M_map[M_map_size/2][0], &M_map[M_map_size/2]);
    181. M_finish = M_start;
    182. }
    183. else
    184. {
    185. M_start--;
    186. *M_start.M_curr = val;
    187. }
    188. }
    189. void push_front(T&& val){
    190. push_front(val);
    191. }
    192. void push_back(T& val){
    193. // 元素存储到了结尾位置
    194. if(M_finish.M_curr == &M_map[M_map_size-1][bufferSize-1])
    195. {
    196. reAlloc(M_map_size * 2);
    197. }
    198. if(M_finish.M_curr == nullptr)
    199. {
    200. M_map[M_map_size/2][0] = val;
    201. M_finish = Iterator(&M_map[M_map_size/2][0],
    202. &M_map[M_map_size/2][0] + bufferSize - 1, &M_map[M_map_size/2][0], &M_map[M_map_size/2]);
    203. M_start = M_finish;
    204. }
    205. else
    206. {
    207. M_finish++;
    208. *M_finish.M_curr = val;
    209. }
    210. }
    211. void push_back(T&& val){
    212. push_back(val);
    213. }
    214. T pop_front()
    215. {
    216. T tmp = *M_start.M_curr;
    217. M_start++;
    218. return tmp;
    219. }
    220. T pop_back()
    221. {
    222. T tmp = *M_finish.M_curr;
    223. M_finish--;
    224. return tmp;
    225. }
    226. Iterator begin()
    227. {
    228. return M_start;
    229. }
    230. Iterator end()
    231. {
    232. return M_finish + 1;
    233. }
    234. int size()
    235. {
    236. return bufferSize *(M_finish.M_map_node - M_start.M_map_node - 1) +
    237. (M_start.M_finish - M_start.M_curr + 1) + (M_finish.M_curr - M_finish.M_start + 1);
    238. }
    239. T& front()
    240. {
    241. return *M_start.M_curr;
    242. }
    243. T& back()
    244. {
    245. return *M_finish.M_curr;
    246. }
    247. void print()
    248. {
    249. for(int i = 0; i < M_map_size; i++)
    250. {
    251. for(int j = 0; j < bufferSize; j++)
    252. {
    253. std::cout << M_map[i][j] <<" ";
    254. }
    255. std::cout << "" << std::endl;
    256. }
    257. }
    258. private:
    259. void reAlloc(int map_size)
    260. {
    261. T** tmp = new T*[map_size];
    262. int ori_mid = M_map_size / 2;
    263. int new_mid = map_size / 2;
    264. tmp[new_mid] = M_map[ori_mid];
    265. // mid to left
    266. int new_index = new_mid - 1;
    267. for(int i = ori_mid - 1; i >= 0; i--)
    268. {
    269. M_map[new_index--] = tmp[i];
    270. }
    271. while (new_index >= 0) {
    272. M_map[new_index--] = new T[bufferSize];
    273. }
    274. // mid to right
    275. new_index = new_mid + 1;
    276. for(int i = ori_mid + 1; i < M_map_size; i++)
    277. {
    278. M_map[new_index++] = tmp[i];
    279. }
    280. while (new_index < map_size) {
    281. M_map[new_index++] = new T[bufferSize];
    282. }
    283. M_map_size = map_size;
    284. T** tmp1 = M_map;
    285. M_map = tmp;
    286. tmp = tmp1;
    287. delete tmp;
    288. }
    289. private:
    290. int M_map_size; // 中控 数组 的长度
    291. T** M_map = nullptr; // 中控数组
    292. Iterator M_start; // 起始元素
    293. Iterator M_finish; // 结尾元素
    294. };
    295. #endif // MY_DEQUE_H
    296. // main.cpp
    297. #include
    298. #include
    299. void testMyDeque()
    300. {
    301. my_deque<int, 3> tmp_deque;
    302. tmp_deque.push_back(1);
    303. // std::cout << " --------- " << std::endl;
    304. // tmp_deque.print();
    305. // std::cout << " --------- " << std::endl;
    306. tmp_deque.push_back(2);
    307. // tmp_deque.print();
    308. // std::cout << " --------- " << std::endl;
    309. tmp_deque.push_back(3);
    310. // tmp_deque.print();
    311. // std::cout << " --------- " << std::endl;
    312. tmp_deque.push_back(4);
    313. // tmp_deque.print();
    314. // std::cout << " --------- " << std::endl;
    315. tmp_deque.push_back(5);
    316. // tmp_deque.print();
    317. // std::cout << " --------- " << std::endl;
    318. tmp_deque.push_front(2);
    319. // tmp_deque.print();
    320. // std::cout << " --------- " << std::endl;
    321. tmp_deque.push_front(3);
    322. // tmp_deque.print();
    323. // std::cout << " --------- " << std::endl;
    324. tmp_deque.push_front(4);
    325. // tmp_deque.print();
    326. // std::cout << " --------- " << std::endl;
    327. tmp_deque.push_front(5);
    328. // tmp_deque.print();
    329. for(my_deque<int, 3>::Iterator iter = tmp_deque.begin(); iter != tmp_deque.end(); iter++)
    330. {
    331. std::cout << *iter << " ";
    332. }
    333. std::cout << " --------- " << std::endl;
    334. auto iter = tmp_deque.begin();
    335. std::cout << *iter <
    336. //std::cout << *(iter-3) <
    337. // std::cout << (iter).M_start <
    338. // std::cout << (iter).M_curr <
    339. // std::cout << (iter).M_finish <
    340. // std::cout << (iter).M_map_node <
    341. std::cout << " --------- " << std::endl;
    342. std::cout << *(iter+3) <
    343. // std::cout << (iter+3).M_start <
    344. // std::cout << (iter+3).M_curr <
    345. // std::cout << (iter+3).M_finish <
    346. // std::cout << (iter+3).M_map_node <
    347. std::cout << " --------- " << std::endl;
    348. auto iter2 = iter + 3;
    349. std::cout << *(iter2-3) <
    350. // std::cout << (iter2-3).M_start <
    351. // std::cout << (iter2-3).M_curr <
    352. // std::cout << (iter2-3).M_finish <
    353. // std::cout << (iter2-3).M_map_node <
    354. std::cout << " --------- " << std::endl;
    355. std::cout << *(iter+5) <
    356. // std::cout << (iter+5).M_start <
    357. // std::cout << (iter+5).M_curr <
    358. // std::cout << (iter+5).M_finish <
    359. // std::cout << (iter+5).M_map_node <
    360. std::cout << "size: " << tmp_deque.size() << std::endl;
    361. std::cout << "pop_back: " << tmp_deque.pop_back() << std::endl;
    362. std::cout << "size: " << tmp_deque.size() << std::endl;
    363. std::cout << "pop_front: " << tmp_deque.pop_front() << std::endl;
    364. std::cout << "size: " << tmp_deque.size() << std::endl;
    365. std::cout << "empty: " << tmp_deque.empty() << std::endl;
    366. }
    367. int main()
    368. {
    369. testMyDeque();
    370. return 0;
    371. }

    输出:

  • 相关阅读:
    js的继承的方式
    含文档+PPT+源码等]精品微信小程序springboot在线考试系统小程序+后台管理系统|前后分离VUE[包运行成功]程序设计源码计算机毕设
    推荐一款.Net Core开发的后台管理系统YiShaAdmin
    软件著作权在哪里查?
    vue中的数据依赖如何追踪收集
    torch.cuda
    行业品牌监测报告|《中国汽车产业舆情报告2022(上半年)》
    innovus: 各种padding一勺烩
    C# list泛型集合(线性表)
    深度学习中的黑科技:自监督学习(Self-Supervised Learning)
  • 原文地址:https://blog.csdn.net/qq_33775774/article/details/133431420