• C++初级----list(STL)


    1、 list介绍

    1.1、 list介绍

    1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 
        1. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向 其前一个元素和后一个元素。 
        2. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高 效。
        3. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率 更好。
        4. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间 开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这 可能是一个重要的因素)

    1.2 、list的使用

    list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展 的能力。以下为list中一些常见的重要接口。

    1.3、list的构造

    构造函数( (constructor))接口说明
    list (size_type n, const value_type& val = value_type())构造的list中包含n个值为val的元素
    list()构造空的list
    list (const list& x)拷贝构造函数
    list (InputIterator first, InputIterator last)用[first, last)区间中的元素构造list

    1.4 list iterator的使用

    函数声明接口说明
    begin + end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
    rbegin + rend返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的 reverse_iterator,即begin位置

    【注意】

    1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

    2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

    1.5 list element access

    1.6 list modifiers

    函数声明接口说明
    push_front 在list首元素前插入值为val的元素
    pop_front 删除list中第一个元素
    push_back在list尾部插入值为val的元素
    pop_back 删除list中最后一个元素
    insert 在list position 位置中插入值为val的元素
    erase 删除list position位置的元素
    swap 交换两个list中的元素
    clear清空list中的有效元素

    1.7 list的迭代器失效

            迭代器失效即迭代器所指向的节点的无效,即该节 点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代 器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

    2、list的模拟实现

    2.1 list的反向迭代器

            通过前面例子知道,反向迭代器的++就是正向迭代器的--,反向迭代器的--就是正向迭代器的++,因此反向迭 代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行 包装即可。

    1. template<class Iterator>
    2. class ReverseListIterator
    3. {
    4. public:
    5. typedef typename Iterator::Ref Ref;
    6. typedef typename Iterator::Ptr Ptr;
    7. typedef ReverseListIterator Self;
    8. public:
    9. // 构造
    10. ReverseListIterator(Iterator it): _it(it) {}
    11. // 具有指针类似行为
    12. Ref operator*()
    13. {
    14. Iterator temp(_it);
    15. --temp;
    16. return *temp;
    17. }
    18. Ptr operator->()
    19. {
    20. return &(operator*());
    21. }
    22. // 迭代器支持移动
    23. Self& operator++()
    24. {
    25. --_it;
    26. return *this;
    27. }
    28. Self operator++(int)
    29. {
    30. Self temp(*this);
    31. --_it;
    32. return temp;
    33. }
    34. Self& operator--()
    35. {
    36. ++_it;
    37. return *this;
    38. }
    39. Self operator--(int)
    40. {
    41. Self temp(*this);
    42. ++_it;
    43. return temp;
    44. }
    45. // 迭代器支持比较
    46. bool operator!=(const Self& l) const
    47. {
    48. return _it != l._it;
    49. }
    50. bool operator==(const Self& l) const
    51. {
    52. return _it != l._it;
    53. }
    54. Iterator _it;
    55. };

    2.2、list的模拟实现

    1. #pragma once
    2. #include
    3. #include
    4. using namespace std;
    5. namespace kzy {
    6. template<class T>
    7. struct list_node {
    8. list_node* _prev;
    9. list_node* _next;
    10. T _data;
    11. list_node(const T& val = T())
    12. :_prev(nullptr)
    13. ,_next(nullptr)
    14. ,_data(val)
    15. {}
    16. };
    17. template<class T, class Ref,class Ptr>
    18. struct _list_iterator
    19. {
    20. typedef list_node Node;
    21. typedef _list_iterator self;
    22. Node* _node;
    23. _list_iterator(Node* node)
    24. :_node(node)
    25. {}
    26. Ref operator*()
    27. {
    28. return _node->_data;
    29. }
    30. Ptr operator->()
    31. {
    32. //return &(operator*());
    33. return &_node->_data;
    34. }
    35. self& operator++()
    36. {
    37. _node=_node->_next;
    38. return *this;
    39. }
    40. self operator++(int)
    41. {
    42. self* tmp(*this);
    43. _node = _node->next;
    44. return tmp;
    45. }
    46. self& operator--()
    47. {
    48. _node = _node->_prev;
    49. return *this;
    50. }
    51. self operator--(int)
    52. {
    53. self* tmp(*this);
    54. _node = _node->_prev;
    55. return tmp;
    56. }
    57. bool operator!=(const self& it)
    58. {
    59. return _node != it._node;
    60. }
    61. bool operator==(const self& it)
    62. {
    63. return _node == it._node;
    64. }
    65. };
    66. template<class T>
    67. class list {
    68. typedef list_node Node;
    69. public:
    70. typedef _list_iterator iterator;
    71. typedef _list_iteratorconst T&, const T*> const_iterator;
    72. const_iterator begin() const
    73. {
    74. return const_iterator(_head->_next);
    75. }
    76. const_iterator end() const
    77. {
    78. return const_iterator(_head);
    79. }
    80. iterator begin()
    81. {
    82. return iterator(_head->_next);
    83. }
    84. iterator end()
    85. {
    86. return iterator(_head);
    87. }
    88. list()
    89. {
    90. _head = new Node();
    91. _head->_next = _head;
    92. _head->_prev = _head;
    93. }
    94. void empty_init()
    95. {
    96. _head = new Node();
    97. _head->_next = _head;
    98. _head->_prev = _head;
    99. }
    100. template <class InputIterator>
    101. list(InputIterator first, InputIterator last)
    102. {
    103. empty_init();
    104. while (first != last)
    105. {
    106. push_back(*first);
    107. ++first;
    108. }
    109. }
    110. void swap(list& lt)
    111. {
    112. std::swap(_head, lt._head);
    113. }
    114. list(const list& it)
    115. {
    116. empty_init();
    117. list tmp = list(it.begin(), it.end());
    118. swap(tmp);
    119. }
    120. list& operator=(list lt)
    121. {
    122. swap(lt);
    123. return *this;
    124. }
    125. ~list()
    126. {
    127. clear();
    128. delete _head;
    129. _head = nullptr;
    130. }
    131. void clear()
    132. {
    133. iterator it = begin();
    134. while (it != end()) {
    135. it=erase(it);
    136. }
    137. }
    138. iterator erase(iterator pos)
    139. {
    140. assert(pos != end());
    141. Node* cur = pos._node;
    142. Node* prev = cur->_prev;
    143. Node* next = cur->_next;
    144. prev->_next = next;
    145. next->_prev = prev;
    146. delete cur;
    147. return iterator(next);
    148. }
    149. void push_back(const T& x)
    150. {
    151. insert(end(),x);
    152. }
    153. void push_front(const T& x)
    154. {
    155. insert(begin(), x);
    156. }
    157. void pop_back()
    158. {
    159. erase(--end());
    160. }
    161. void pop_front()
    162. {
    163. erase(begin());
    164. }
    165. iterator insert(iterator pos, const T& x)
    166. {
    167. Node* newnode = new Node(x);
    168. Node* cur = pos._node;
    169. Node* prev = cur->_prev;
    170. prev->_next = newnode;
    171. newnode->_prev = prev;
    172. newnode->_next = cur;
    173. cur->_prev = newnode;
    174. return iterator(newnode);
    175. }
    176. private:
    177. Node* _head;
    178. };
    179. void print_list(const list<int>& lt)
    180. {
    181. list<int>::const_iterator it = lt.begin();
    182. while (it != lt.end())
    183. {
    184. //*it = 10; // 不允许修改
    185. cout << *it << " ";
    186. ++it;
    187. }
    188. cout << endl;
    189. }
    190. void test_list1()
    191. {
    192. list<int> lt;
    193. lt.push_back(1);
    194. lt.push_back(2);
    195. lt.push_back(3);
    196. lt.push_back(4);
    197. list<int>::iterator it = lt.begin();
    198. while (it != lt.end())
    199. {
    200. *it = 20;
    201. cout << *it << " ";
    202. ++it;
    203. }
    204. cout << endl;
    205. print_list(lt);
    206. }
    207. struct AA
    208. {
    209. AA(int a1 = 0, int a2 = 0)
    210. :_a1(a1)
    211. , _a2(a2)
    212. {}
    213. int _a1;
    214. int _a2;
    215. };
    216. void test_list2()
    217. {
    218. list lt;
    219. lt.push_back(AA(1, 1));
    220. lt.push_back(AA(2, 2));
    221. lt.push_back(AA(3, 3));
    222. lt.push_back(AA(4, 4));
    223. // 迭代器模拟的是指针行为
    224. // int* it *it
    225. // AA* it *it it->
    226. list::iterator it = lt.begin();
    227. while (it != lt.end())
    228. {
    229. //cout << (*it)._a1 << "-"<< (*it)._a2 <<" ";
    230. cout << it->_a1 << "-" << it->_a2 << " ";
    231. ++it;
    232. }
    233. cout << endl;
    234. }
    235. void test_list3()
    236. {
    237. list<int> lt;
    238. lt.push_back(1);
    239. lt.push_back(2);
    240. lt.push_back(3);
    241. lt.push_back(4);
    242. lt.push_front(1);
    243. lt.push_front(2);
    244. lt.push_front(3);
    245. lt.push_front(4);
    246. for (auto e : lt)
    247. {
    248. cout << e << " ";
    249. }
    250. cout << endl;
    251. lt.pop_front();
    252. lt.pop_front();
    253. lt.pop_back();
    254. lt.pop_back();
    255. for (auto e : lt)
    256. {
    257. cout << e << " ";
    258. }
    259. cout << endl;
    260. }
    261. void test_list4()
    262. {
    263. list<int> lt;
    264. lt.push_back(1);
    265. lt.push_back(2);
    266. lt.push_back(2);
    267. lt.push_back(3);
    268. lt.push_back(4);
    269. lt.push_back(5);
    270. lt.push_back(6);
    271. // 要求在偶数的前面插入这个偶数*10
    272. auto it1 = lt.begin();
    273. while (it1 != lt.end())
    274. {
    275. if (*it1 % 2 == 0)
    276. {
    277. lt.insert(it1, *it1 * 10);
    278. }
    279. ++it1;
    280. }
    281. for (auto e : lt)
    282. {
    283. cout << e << " ";
    284. }
    285. cout << endl;
    286. }
    287. void test_list5()
    288. {
    289. list<int> lt;
    290. lt.push_back(1);
    291. lt.push_back(2);
    292. lt.push_back(2);
    293. lt.push_back(3);
    294. lt.push_back(4);
    295. lt.push_back(5);
    296. lt.push_back(6);
    297. // 删除所有的偶数
    298. /*auto it1 = lt.begin();
    299. while (it1 != lt.end())
    300. {
    301. if (*it1 % 2 == 0)
    302. {
    303. lt.erase(it1);
    304. }
    305. ++it1;
    306. }*/
    307. auto it1 = lt.begin();
    308. while (it1 != lt.end())
    309. {
    310. if (*it1 % 2 == 0)
    311. {
    312. it1 = lt.erase(it1);
    313. }
    314. else
    315. {
    316. ++it1;
    317. }
    318. }
    319. for (auto e : lt)
    320. {
    321. cout << e << " ";
    322. }
    323. cout << endl;
    324. lt.clear();
    325. for (auto e : lt)
    326. {
    327. cout << e << " ";
    328. }
    329. cout << endl;
    330. lt.push_back(10);
    331. lt.push_back(20);
    332. lt.push_back(30);
    333. for (auto e : lt)
    334. {
    335. cout << e << " ";
    336. }
    337. cout << endl;
    338. }
    339. void test_list6()
    340. {
    341. list<int> lt;
    342. lt.push_back(1);
    343. lt.push_back(2);
    344. lt.push_back(3);
    345. lt.push_back(4);
    346. lt.push_back(5);
    347. lt.push_back(6);
    348. list<int> lt1(lt);
    349. for (auto e : lt1)
    350. {
    351. cout << e << " ";
    352. }
    353. cout << endl;
    354. for (auto e : lt)
    355. {
    356. cout << e << " ";
    357. }
    358. cout << endl;
    359. list<int> lt2;
    360. lt2.push_back(10);
    361. lt2.push_back(20);
    362. lt1 = lt2;
    363. for (auto e : lt2)
    364. {
    365. cout << e << " ";
    366. }
    367. cout << endl;
    368. for (auto e : lt1)
    369. {
    370. cout << e << " ";
    371. }
    372. cout << endl;
    373. }
    374. }

    3、list和vector对比

    vector

    list

    底层结构

    动态顺序表,一段连续空间

    带头结点的双向循环链表

    随机访问

    支持随机访问,访问某个元素效率O(1)

    不支持随机访问,访问某个元素效率O(N)

    插入和删除

    任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低

    任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1)

    空间利用率

    底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高

    底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低

    迭代器

    原生态指针

    对原生态指针(节点指针)进行封装

    迭代器失效

    在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效

    插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响

    使用场景

    需要高效存储,支持随机访问,不关心插入删除效率

    大量插入和删除操作,不关心随机访

  • 相关阅读:
    【JAVA数据结构】JAVA数据结构必备知识:泛型与包装类
    echarts和v-chart柱状图颜色渐变
    ESXI配置免密登录
    【23真题】准考证抄出来的题目,还原度99%以上!
    Compose和AndroidView的交互
    微信小程序开发实战-setData字段特别多时怎么办,试试动态遍历字段并提取赋值
    关于淘宝多个关键词权重快速提升的方法介绍
    板刷codeforces 1000分
    微擎模块 疯狂诗词大会小程序 2.0 前端+后端 优化答题正确提示页面样式
    Kubernetes kafka系列 | k8s部署kafka+zookeepe集群
  • 原文地址:https://blog.csdn.net/weixin_63219391/article/details/137889979