STL源码分析--list

相较于vector的连续线性空间,list就显得复杂许多,它的好处是每次插入或删除一个元素,就配置或释放一个元素空间。因此,list对于空间的运用有绝对的精准,一点也不浪费。而且,对于任何位置的元素插入或元素移除,list永远是常数时间。

list不仅是一个双向链表,而且还是一个环状双向链表。另外,还有一个重要性质,插入操作和接合操作都不会造成原有的list迭代器失效,这在vector是不成立的。因为vector的插入操作可能造成记忆体重新配置,导致原有的迭代器全部失效。甚至list的元素删除操作(erase),也只有“指向被删除元素”的那个迭代器失效,其他迭代器不受任何影响。

以下是list的节点、迭代器数据结构设计以及list的源码剖析:

[cpp] view plaincopy

  1. ////////////////////////////////////////////////////////////////////////////////
  2. // list结点, 提供双向访问能力
  3. ////////////////////////////////////////////////////////////////////////////////
  4. //  --------           --------           --------           --------
  5. //  | next |---------->| next |---------->| next |---------->| next |
  6. //  --------           --------           --------           --------
  7. //  | prev |<----------| prev |<----------| prev |<----------| prev |
  8. //  --------           --------           --------           --------
  9. //  | data |           | data |           | data |           | data |
  10. //  --------           --------           --------           --------
  11. ////////////////////////////////////////////////////////////////////////////////
  12. template <class T>
  13. struct __list_node
  14. {
  15. typedef void* void_pointer;
  16. void_pointer next;
  17. void_pointer prev;
  18. T data;
  19. };
  20. // 至于为什么不使用默认参数, 这个是因为有一些编译器不能提供推导能力,
  21. // 而作者又不想维护两份代码, 故不使用默认参数
  22. template<class T, class Ref, class Ptr>
  23. struct __list_iterator
  24. {
  25. typedef __list_iterator<T, T&, T*>             iterator;   // STL标准强制要求
  26. typedef __list_iterator<T, Ref, Ptr>           self;
  27. typedef bidirectional_iterator_tag iterator_category;
  28. typedef T value_type;
  29. typedef Ptr pointer;
  30. typedef Ref reference;
  31. typedef __list_node<T>* link_type;
  32. typedef size_t size_type;
  33. typedef ptrdiff_t difference_type;
  34. link_type node;   //迭代器内部当然要有一个普通指针,指向list的节点
  35. __list_iterator(link_type x) : node(x) {}
  36. __list_iterator() {}
  37. __list_iterator(const iterator& x) : node(x.node) {}
  38. // 在STL算法中需要迭代器提供支持
  39. bool operator==(const self& x) const { return node == x.node; }
  40. bool operator!=(const self& x) const { return node != x.node; }
  41. // 以下对迭代器取值(dereference),取的是节点的数据值
  42. reference operator*() const { return (*node).data; }
  43. // 以下是迭代器的成员存取运算子的标准做法
  44. pointer operator->() const { return &(operator*()); }
  45. // 前缀自加,对迭代器累加1,就是前进一个节点
  46. self& operator++()
  47. {
  48. node = (link_type)((*node).next);
  49. return *this;
  50. }
  51. // 后缀自加, 需要先产生自身的一个副本, 然会再对自身操作, 最后返回副本
  52. self operator++(int)
  53. {
  54. self tmp = *this;
  55. ++*this;
  56. return tmp;
  57. }
  58. // 前缀自减
  59. self& operator--()
  60. {
  61. node = (link_type)((*node).prev);
  62. return *this;
  63. }
  64. self operator--(int)
  65. {
  66. self tmp = *this;
  67. --*this;
  68. return tmp;
  69. }
  70. };
  71. ////////////////////////////////////////////////////////////////////////////////
  72. // list不仅是个双向链表, 而且还是一个环状双向链表
  73. ////////////////////////////////////////////////////////////////////////////////
  74. //       end()              头结点             begin()
  75. //         ↓                  ↓                  ↓
  76. //      --------           --------           --------           --------
  77. // ---->| next |---------->| next |---------->| next |---------->| next |------
  78. // |    --------           --------           --------           --------     |
  79. // |  --| prev |<----------| prev |<----------| prev |<----------| prev |<--| |
  80. // |  | --------           --------           --------           --------   | |
  81. // |  | | data |           | data |           | data |           | data |   | |
  82. // |  | --------           --------           --------           --------   | |
  83. // |  |                                                                     | |
  84. // |  | --------           --------           --------           --------   | |
  85. // ---|-| next |<----------| next |<----------| next |<----------| next |<--|--
  86. //    | --------           --------           --------           --------   |
  87. //    ->| prev |---------->| prev |---------->| prev |---------->| prev |----
  88. //      --------           --------           --------           --------
  89. //      | data |           | data |           | data |           | data |
  90. //      --------           --------           --------           --------
  91. ////////////////////////////////////////////////////////////////////////////////
  92. // 默认allocator为alloc, 其具体使用版本请参照<stl_alloc.h>
  93. template <class T, class Alloc = alloc>
  94. class list
  95. {
  96. protected:
  97. typedef void* void_pointer;
  98. typedef __list_node<T> list_node;
  99. // 专属之空间配置器,每次配置一个节点大小
  100. typedef simple_alloc<list_node, Alloc> list_node_allocator;
  101. public:
  102. typedef T value_type;
  103. typedef value_type* pointer;
  104. typedef value_type& reference;
  105. typedef list_node* link_type;
  106. typedef size_t size_type;
  107. typedef ptrdiff_t difference_type;
  108. typedef __list_iterator<T, T&, T*>             iterator;
  109. protected:
  110. link_type node ;     // 只要一个指针,便可表示整个环状双向链表
  111. // 分配一个新结点, 注意这里并不进行构造,
  112. // 构造交给全局的construct, 见<stl_stl_uninitialized.h>
  113. link_type get_node() { return list_node_allocator::allocate(); }
  114. // 释放指定结点, 不进行析构, 析构交给全局的destroy
  115. void put_node(link_type p) { list_node_allocator::deallocate(p); }
  116. // 产生(配置并构造)一个节点, 首先分配内存, 然后进行构造
  117. // 注: commit or rollback
  118. link_type create_node(const T& x)
  119. {
  120. link_type p = get_node();
  121. construct(&p->data, x);
  122. return p;
  123. }
  124. // 析构结点元素, 并释放内存
  125. void destroy_node(link_type p)
  126. {
  127. destroy(&p->data);
  128. put_node(p);
  129. }
  130. protected:
  131. // 用于空链表的建立
  132. void empty_initialize()
  133. {
  134. node = get_node();   // 配置一个节点空间,令node指向它
  135. node->next = node;   // 令node头尾都指向自己,不设元素值
  136. node->prev = node;
  137. }
  138. // 创建值为value共n个结点的链表
  139. // 注: commit or rollback
  140. void fill_initialize(size_type n, const T& value)
  141. {
  142. empty_initialize();
  143. __STL_TRY
  144. {
  145. // 此处插入操作时间复杂度O(1)
  146. insert(begin(), n, value);
  147. }
  148. __STL_UNWIND(clear(); put_node(node));
  149. }
  150. public:
  151. list() { empty_initialize(); }
  152. iterator begin() { return (link_type)((*node).next); }
  153. // 链表成环, 当指所以头节点也就是end
  154. iterator end() { return node; }
  155. // 头结点指向自身说明链表中无元素
  156. bool empty() const { return node->next == node; }
  157. // 使用全局函数distance()进行计算, 时间复杂度O(n)
  158. size_type size() const
  159. {
  160. size_type result = 0;
  161. distance(begin(), end(), result);
  162. return result;
  163. }
  164. size_type max_size() const { return size_type(-1); }
  165. reference front() { return *begin(); }
  166. reference back() { return *(--end()); }
  167. ////////////////////////////////////////////////////////////////////////////////
  168. // 在指定位置插入元素
  169. ////////////////////////////////////////////////////////////////////////////////
  170. //       insert(iterator position, const T& x)
  171. //                       ↓
  172. //                 create_node(x)
  173. //                 p = get_node();-------->list_node_allocator::allocate();
  174. //                 construct(&p->data, x);
  175. //                       ↓
  176. //            tmp->next = position.node;
  177. //            tmp->prev = position.node->prev;
  178. //            (link_type(position.node->prev))->next = tmp;
  179. //            position.node->prev = tmp;
  180. ////////////////////////////////////////////////////////////////////////////////
  181. iterator insert(iterator position, const T& x)
  182. {
  183. link_type tmp = create_node(x);   // 产生一个节点
  184. // 调整双向指针,使tmp插入进去
  185. tmp->next = position.node;
  186. tmp->prev = position.node->prev;
  187. (link_type(position.node->prev))->next = tmp;
  188. position.node->prev = tmp;
  189. return tmp;
  190. }
  191. // 指定位置插入n个值为x的元素, 详细解析见实现部分
  192. void insert(iterator pos, size_type n, const T& x);
  193. void insert(iterator pos, int n, const T& x)
  194. {
  195. insert(pos, (size_type)n, x);
  196. }
  197. void insert(iterator pos, long n, const T& x)
  198. {
  199. insert(pos, (size_type)n, x);
  200. }
  201. // 在链表前端插入结点
  202. void push_front(const T& x) { insert(begin(), x); }
  203. // 在链表最后插入结点
  204. void push_back(const T& x) { insert(end(), x); }
  205. // 移除迭代器position所指节点
  206. iterator erase(iterator position)
  207. {
  208. link_type next_node = link_type(position.node->next);
  209. link_type prev_node = link_type(position.node->prev);
  210. prev_node->next = next_node;
  211. next_node->prev = prev_node;
  212. destroy_node(position.node);
  213. return iterator(next_node);
  214. }
  215. // 擦除一个区间的结点, 详细解析见实现部分
  216. iterator erase(iterator first, iterator last);
  217. void resize(size_type new_size, const T& x);
  218. void resize(size_type new_size) { resize(new_size, T()); }
  219. void clear();
  220. // 删除链表第一个结点
  221. void pop_front() { erase(begin()); }
  222. // 删除链表最后一个结点
  223. void pop_back()
  224. {
  225. iterator tmp = end();
  226. erase(--tmp);
  227. }
  228. list(size_type n, const T& value) { fill_initialize(n, value); }
  229. list(int n, const T& value) { fill_initialize(n, value); }
  230. list(long n, const T& value) { fill_initialize(n, value); }
  231. ~list()
  232. {
  233. // 释放所有结点  // 使用全局函数distance()进行计算, 时间复杂度O(n)
  234. size_type size() const
  235. {
  236. size_type result = 0;
  237. distance(begin(), end(), result);
  238. return result;
  239. }
  240. clear();
  241. // 释放头结点
  242. put_node(node);
  243. }
  244. list<T, Alloc>& operator=(const list<T, Alloc>& x);
  245. protected:
  246. ////////////////////////////////////////////////////////////////////////////////
  247. // 将[first, last)内的所有元素移动到position之前
  248. // 如果last == position, 则相当于链表不变化, 不进行操作
  249. ////////////////////////////////////////////////////////////////////////////////
  250. // 初始状态
  251. //                   first                             last
  252. //                     ↓                                 ↓
  253. //      --------   --------   --------     --------   --------   --------
  254. //      | next |-->| next |-->| next |     | next |-->| next |-->| next |
  255. //  ... --------   --------   -------- ... --------   --------   -------- ...
  256. //      | prev |<--| prev |<--| prev |     | prev |<--| prev |<--| prev |
  257. //      --------   --------   --------     --------   --------   --------
  258. //
  259. //                           position
  260. //                               ↓
  261. //      --------   --------   --------   --------   --------   --------
  262. //      | next |-->| next |-->| next |-->| next |-->| next |-->| next |
  263. //  ... --------   --------   --------   --------   --------   -------- ...
  264. //      | prev |<--| prev |<--| prev |<--| prev |<--| prev |<--| prev |
  265. //      --------   --------   --------   --------   --------   --------
  266. //
  267. // 操作完成后状态
  268. //                           first
  269. //                             |
  270. //               --------------|--------------------------------------
  271. //               | ------------|------------------------------------ |   last
  272. //               | |           ↓                                   | |     ↓
  273. //      -------- | |        --------   --------     --------       | |  --------   --------
  274. //      | next |-- |  ----->| next |-->| next |     | next |-----  | -->| next |-->| next |
  275. //  ... --------   |  |     --------   -------- ... --------    |  |    --------   -------- ...
  276. //      | prev |<---  |  ---| prev |<--| prev |     | prev |<-- |  -----| prev |<--| prev |
  277. //      --------      |  |  --------   --------     --------  | |       --------   --------
  278. //                    |  |                                    | |
  279. //                    |  ------                               | |
  280. //                    ------- |  ------------------------------ |
  281. //                          | |  |                              |
  282. //                          | |  |  -----------------------------
  283. //                          | |  |  |
  284. //                          | |  |  |  position
  285. //                          | |  |  |     ↓
  286. //      --------   -------- | |  |  |  --------   --------   --------   --------
  287. //      | next |-->| next |-- |  |  -->| next |-->| next |-->| next |-->| next |
  288. //  ... --------   --------   |  |     --------   --------   --------   -------- ...
  289. //      | prev |<--| prev |<---  ------| prev |<--| prev |<--| prev |<--| prev |
  290. //      --------   --------            --------   --------   --------   --------
  291. ////////////////////////////////////////////////////////////////////////////////
  292. void transfer(iterator position, iterator first, iterator last)
  293. {
  294. if (position != last)   // 如果last == position, 则相当于链表不变化, 不进行操作
  295. {
  296. (*(link_type((*last.node).prev))).next = position.node;
  297. (*(link_type((*first.node).prev))).next = last.node;
  298. (*(link_type((*position.node).prev))).next = first.node;
  299. link_type tmp = link_type((*position.node).prev);
  300. (*position.node).prev = (*last.node).prev;
  301. (*last.node).prev = (*first.node).prev;
  302. (*first.node).prev = tmp;
  303. }
  304. }
  305. public:
  306. // 将链表x移动到position所指位置之前
  307. void splice(iterator position, list& x)
  308. {
  309. if (!x.empty())
  310. transfer(position, x.begin(), x.end());
  311. }
  312. // 将链表中i指向的内容移动到position之前
  313. void splice(iterator position, list&, iterator i)
  314. {
  315. iterator j = i;
  316. ++j;
  317. if (position == i || position == j) return;
  318. transfer(position, i, j);
  319. }
  320. // 将[first, last}元素移动到position之前
  321. void splice(iterator position, list&, iterator first, iterator last)
  322. {
  323. if (first != last)
  324. transfer(position, first, last);
  325. }
  326. void remove(const T& value);
  327. void unique();
  328. void merge(list& x);
  329. void reverse();
  330. void sort();
  331. };
  332. // 销毁所有结点, 将链表置空
  333. template <class T, class Alloc>
  334. void list<T, Alloc>::clear()
  335. {
  336. link_type cur = (link_type) node->next;
  337. while (cur != node)
  338. {
  339. link_type tmp = cur;
  340. cur = (link_type) cur->next;
  341. destroy_node(tmp);
  342. }
  343. // 恢复node原始状态
  344. node->next = node;
  345. node->prev = node;
  346. }
  347. // 链表赋值操作
  348. // 如果当前容器元素少于x容器, 则析构多余元素,
  349. // 否则将调用insert插入x中剩余的元素
  350. template <class T, class Alloc>
  351. list<T, Alloc>& list<T, Alloc>::operator=(const list<T, Alloc>& x)
  352. {
  353. if (this != &x)
  354. {
  355. iterator first1 = begin();
  356. iterator last1 = end();
  357. const_iterator first2 = x.begin();
  358. const_iterator last2 = x.end();
  359. while (first1 != last1 && first2 != last2) *first1++ = *first2++;
  360. if (first2 == last2)
  361. erase(first1, last1);
  362. else
  363. insert(last1, first2, last2);
  364. }
  365. return *this;
  366. }
  367. // 移除容器内所有的相邻的重复结点
  368. // 时间复杂度O(n)
  369. // 用户自定义数据类型需要提供operator ==()重载
  370. template <class T, class Alloc>
  371. void list<T, Alloc>::unique()
  372. {
  373. iterator first = begin();
  374. iterator last = end();
  375. if (first == last) return;
  376. iterator next = first;
  377. while (++next != last)
  378. {
  379. if (*first == *next)
  380. erase(next);
  381. else
  382. first = next;
  383. next = first;
  384. }
  385. }
  386. // 假设当前容器和x都已序, 保证两容器合并后仍然有序
  387. template <class T, class Alloc>
  388. void list<T, Alloc>::merge(list<T, Alloc>& x)
  389. {
  390. iterator first1 = begin();
  391. iterator last1 = end();
  392. iterator first2 = x.begin();
  393. iterator last2 = x.end();
  394. // 注意:前提是,两个lists都已经递增排序
  395. while (first1 != last1 && first2 != last2)
  396. if (*first2 < *first1)
  397. {
  398. iterator next = first2;
  399. transfer(first1, first2, ++next);
  400. first2 = next;
  401. }
  402. else
  403. ++first1;
  404. if (first2 != last2)
  405. transfer(last1, first2, last2);
  406. }
时间: 2024-11-11 13:23:10

STL源码分析--list的相关文章

stl源码分析之hash table

本文主要分析g++ stl中哈希表的实现方法.stl中,除了以红黑树为底层存储结构的map和set,还有用哈希表实现的hash_map和hash_set.map和set的查询时间是对数级的,而hash_map和hash_set更快,可以达到常数级,不过哈希表需要更多内存空间,属于以空间换时间的用法,而且选择一个好的哈希函数也不那么容易. 一. 哈希表基本概念 哈希表,又名散列表,是根据关键字直接访问内存的数据结构.通过哈希函数,将键值映射转换成数组中的位置,就可以在O(1)的时间内访问到数据.举

stl源码分析之list

本文主要分析gcc4.8版本的stl list的源码实现,与vector的线性空间结构不同,list的节点是任意分散的,节点之间通过指针连接,好处是在任何位置插入删除元素都只需要常数时间,缺点是不能随机访问,查询复杂度是O(n),n为list中的元素个数.所以list非常适合应用与数据插入删除频繁的场景. 一. list节点 list节点定义如下, struct _List_node_base { _List_node_base* _M_next; _List_node_base* _M_pre

STL源码分析--仿函数 &amp; 配接器

STL源码分析-仿函数 & 配接器 仿函数就是函数对象.就实现观点而言,仿函数其实就是一个"行为类似函数"的对象.为了能够"行为类似函数",其类别定义中必须自定义(或说改写.重载)function call 运算子(operator()),拥有这样的运算子后,我们就可以在仿函数的对象后面加上一对小括号,以此调用仿函数所定义的operator().仿函数作为可配接的关键因素. 配接器在STL组件的灵活组合运用功能上,扮演着轴承.转换器的角色,adapter的定

stl源码分析之priority queue

前面两篇介绍了gcc4.8的vector和list的源码实现,这是stl最常用了两种序列式容器.除了容器之外,stl还提供了一种借助容器实现特殊操作的组件,谓之适配器,比如stack,queue,priority queue等,本文就介绍gcc4.8的priority queue的源码实现. 顾名思义,priority queue是带有优先级的队列,所以元素必须提供<操作符,与vector和list不同,priority queue允许加入元素,但是取出时只能取出优先级最高的元素. 一. pri

stl源码分析之vector

上篇简单介绍了gcc4.8提供的几种allocator的实现方法和作用,这是所有stl组件的基础,容器必须通过allocator申请分配内存和释放内存,至于底层是直接分配释放内存还是使用内存池等方法就不是组件需要考虑的事情.这篇文章开始分析gcc4.8 stl的容器源码实现.stl的容器分为序列式容器和关联式容器,前者包括vector,list,queue以及stack等常用数据结构,后者包含了map,set以及hash table等比较高级的结构,本文就从使用最广泛也是最基础的vector开始

STL源码分析--空间配置器的底层实现 (二)

STL源码分析-空间配置器 空间配置器中门道 在STL中的容器里都是使用统一的空间配置器,空间配置器就是管理分配内存和销毁内存的.在STL将在heap空间创建一个对象分为两个步骤,第一是申请一块内存,第二是在这块内存中初始化一个对象.首先申请空间是由malloc提供,初始化一个对象时由constructor管理.销毁一个对象也是由两步骤完成,第一是销毁空间上的对象,第二是释放这块内存. 同时,STL的空间配置器分为两级内存,如果申请的内存空间大于128KB,那么就使用第一级空间配置,如果小于,那

STL源码分析--仿函数 &amp; 模板的模板参数 &amp; 临时对象

STL源码分析-使用的一些特殊语法 关于泛型编程中用到的一些特殊语法,这些语法也适用于平常的模板编程 1.  类模板中使用静态成员变量 Static成员变量在类模板中并不是很特殊,同时这个变量不属于对象,属于实例化以后的这个类类型.每一个实例化对应一个static变量 2.  类模板中可以再有模板成员 3.  模板参数可以根据前一个模板参数而设定默认值 4.  类模板可以拥有非类型的模板参数 所谓非类型的模板参数就是内建型的模板参数 Template <class T,class Alloc =

STL 源码分析 # stl_iterator &amp; stl_iterator_base #

STL 源码分析 # stl_iterator_base && stl_iterator # 这里能很清楚的看到各个基础类型的继承关系 template <class _Tp, class _Distance> struct input_iterator { typedef input_iterator_tag iterator_category; typedef _Tp value_type; typedef _Distance difference_type; typede

STL源码分析--萃取编程(traits)技术的实现

1.为什么要出现? 按照默认认定,一个模板给出了一个单一的定义,可以用于用户可以想到的任何模板参数!但是对于写模板的人而言,这种方式并不灵活,特别是遇到模板参数为指针时,若想实现与类型的参量不一样的实例化,就变得不太可能了!也有时,想禁止此种相同的实例化变得不太可能!故而出现了,Partial Specialization! 同时,在使用void*指针时,可以最大限度的共享代码,减少代码的膨胀! 2.它是什么?其实,就是用户定义的偏特化.用template<>来说明这是一个偏特化,针对任何模板

STL源码分析--算法

STL源码剖析-算法 在STL中的算法中一些算法是可以根据算法名字来判断算法作用的.所有算法的参数都是迭代器,不过不同的算法调用的迭代器类型也是不同的.多有的STL算法都作用在由迭代器{first,lase)所表示出来的区间上.拷贝(copy)交换(swap)替换(replace)填写(fill)删除(remove)排列组合(permutation)分割(partition)随机重排(random shuffling)排序(sort)计算(accumulate)计数(count)匹配(searc