相较于vector的连续线性空间,list就显得复杂许多,它的好处是每次插入或删除一个元素,就配置或释放一个元素空间。因此,list对于空间的运用有绝对的精准,一点也不浪费。而且,对于任何位置的元素插入或元素移除,list永远是常数时间。
      list不仅是一个双向链表,而且还是一个环状双向链表。另外,还有一个重要性质,插入操作和接合操作都不会造成原有的list迭代器失效,这在vector是不成立的。因为vector的插入操作可能造成记忆体重新配置,导致原有的迭代器全部失效。甚至list的元素删除操作(erase),也只有“指向被删除元素”的那个迭代器失效,其他迭代器不受任何影响。
以下是list的节点、迭代器数据结构设计以及list的源码剖析:


// list结点, 提供双向访问能力//  --------           --------           --------           --------
//  | next |---------->| next |---------->| next |---------->| next |
//  --------           --------           --------           --------
//  | prev |<----------| prev |<----------| prev |<----------| prev |
//  --------           --------           --------           --------
//  | data |           | data |           | data |           | data |
//  --------           --------           --------           --------template <class T>
struct __list_node
{typedef void* void_pointer;void_pointer next;void_pointer prev;T data;
};// 至于为什么不使用默认参数, 这个是因为有一些编译器不能提供推导能力,
// 而作者又不想维护两份代码, 故不使用默认参数
template<class T, class Ref, class Ptr>
struct __list_iterator
{typedef __list_iterator<T, T&, T*>             iterator;   // STL标准强制要求typedef __list_iterator<T, Ref, Ptr>           self;typedef bidirectional_iterator_tag iterator_category;typedef T value_type;typedef Ptr pointer;typedef Ref reference;typedef __list_node<T>* link_type;typedef size_t size_type;typedef ptrdiff_t difference_type;link_type node;   //迭代器内部当然要有一个普通指针,指向list的节点__list_iterator(link_type x) : node(x) {}__list_iterator() {}__list_iterator(const iterator& x) : node(x.node) {}// 在STL算法中需要迭代器提供支持bool operator==(const self& x) const { return node == x.node; }bool operator!=(const self& x) const { return node != x.node; }// 以下对迭代器取值(dereference),取的是节点的数据值reference operator*() const { return (*node).data; }// 以下是迭代器的成员存取运算子的标准做法pointer operator->() const { return &(operator*()); }// 前缀自加,对迭代器累加1,就是前进一个节点self& operator++(){node = (link_type)((*node).next);return *this;}// 后缀自加, 需要先产生自身的一个副本, 然会再对自身操作, 最后返回副本self operator++(int){self tmp = *this;++*this;return tmp;}// 前缀自减self& operator--(){node = (link_type)((*node).prev);return *this;}self operator--(int){self tmp = *this;--*this;return tmp;}
};// list不仅是个双向链表, 而且还是一个环状双向链表//       end()              头结点             begin()
//         ↓                  ↓                  ↓
//      --------           --------           --------           --------
// ---->| next |---------->| next |---------->| next |---------->| next |------
// |    --------           --------           --------           --------     |
// |  --| prev |<----------| prev |<----------| prev |<----------| prev |<--| |
// |  | --------           --------           --------           --------   | |
// |  | | data |           | data |           | data |           | data |   | |
// |  | --------           --------           --------           --------   | |
// |  |                                                                     | |
// |  | --------           --------           --------           --------   | |
// ---|-| next |<----------| next |<----------| next |<----------| next |<--|--
//    | --------           --------           --------           --------   |
//    ->| prev |---------->| prev |---------->| prev |---------->| prev |----
//      --------           --------           --------           --------
//      | data |           | data |           | data |           | data |
//      --------           --------           --------           --------// 默认allocator为alloc, 其具体使用版本请参照<stl_alloc.h>
template <class T, class Alloc = alloc>
class list
{
protected:typedef void* void_pointer;typedef __list_node<T> list_node;// 专属之空间配置器,每次配置一个节点大小typedef simple_alloc<list_node, Alloc> list_node_allocator;public:typedef T value_type;typedef value_type* pointer;typedef value_type& reference;typedef list_node* link_type;typedef size_t size_type;typedef ptrdiff_t difference_type;typedef __list_iterator<T, T&, T*>             iterator;protected:link_type node ;     // 只要一个指针,便可表示整个环状双向链表// 分配一个新结点, 注意这里并不进行构造,// 构造交给全局的construct, 见<stl_stl_uninitialized.h>link_type get_node() { return list_node_allocator::allocate(); }// 释放指定结点, 不进行析构, 析构交给全局的destroyvoid put_node(link_type p) { list_node_allocator::deallocate(p); }// 产生(配置并构造)一个节点, 首先分配内存, 然后进行构造// 注: commit or rollbacklink_type create_node(const T& x){link_type p = get_node();construct(&p->data, x);return p;}// 析构结点元素, 并释放内存void destroy_node(link_type p){destroy(&p->data);put_node(p);}protected:// 用于空链表的建立void empty_initialize(){node = get_node();   // 配置一个节点空间,令node指向它node->next = node;   // 令node头尾都指向自己,不设元素值node->prev = node;}// 创建值为value共n个结点的链表// 注: commit or rollbackvoid fill_initialize(size_type n, const T& value){empty_initialize();__STL_TRY{// 此处插入操作时间复杂度O(1)insert(begin(), n, value);}__STL_UNWIND(clear(); put_node(node));}public:list() { empty_initialize(); }iterator begin() { return (link_type)((*node).next); }// 链表成环, 当指所以头节点也就是enditerator end() { return node; }// 头结点指向自身说明链表中无元素bool empty() const { return node->next == node; }// 使用全局函数distance()进行计算, 时间复杂度O(n)size_type size() const{size_type result = 0;distance(begin(), end(), result);return result;}size_type max_size() const { return size_type(-1); }reference front() { return *begin(); }reference back() { return *(--end()); }// 在指定位置插入元素//       insert(iterator position, const T& x)//                       ↓//                 create_node(x)//                 p = get_node();-------->list_node_allocator::allocate();//                 construct(&p->data, x);//                       ↓//            tmp->next = position.node;//            tmp->prev = position.node->prev;//            (link_type(position.node->prev))->next = tmp;//            position.node->prev = tmp;iterator insert(iterator position, const T& x){link_type tmp = create_node(x);   // 产生一个节点// 调整双向指针,使tmp插入进去tmp->next = position.node;tmp->prev = position.node->prev;(link_type(position.node->prev))->next = tmp;position.node->prev = tmp;return tmp;}// 指定位置插入n个值为x的元素, 详细解析见实现部分void insert(iterator pos, size_type n, const T& x);void insert(iterator pos, int n, const T& x){insert(pos, (size_type)n, x);}void insert(iterator pos, long n, const T& x){insert(pos, (size_type)n, x);}// 在链表前端插入结点void push_front(const T& x) { insert(begin(), x); }// 在链表最后插入结点void push_back(const T& x) { insert(end(), x); }// 移除迭代器position所指节点iterator erase(iterator position){link_type next_node = link_type(position.node->next);link_type prev_node = link_type(position.node->prev);prev_node->next = next_node;next_node->prev = prev_node;destroy_node(position.node);return iterator(next_node);}// 擦除一个区间的结点, 详细解析见实现部分iterator erase(iterator first, iterator last);void resize(size_type new_size, const T& x);void resize(size_type new_size) { resize(new_size, T()); }void clear();// 删除链表第一个结点void pop_front() { erase(begin()); }// 删除链表最后一个结点void pop_back(){iterator tmp = end();erase(--tmp);}list(size_type n, const T& value) { fill_initialize(n, value); }list(int n, const T& value) { fill_initialize(n, value); }list(long n, const T& value) { fill_initialize(n, value); }~list(){// 释放所有结点  // 使用全局函数distance()进行计算, 时间复杂度O(n)size_type size() const{size_type result = 0;distance(begin(), end(), result);return result;}clear();// 释放头结点put_node(node);}list<T, Alloc>& operator=(const list<T, Alloc>& x);protected:// 将[first, last)内的所有元素移动到position之前// 如果last == position, 则相当于链表不变化, 不进行操作// 初始状态//                   first                             last//                     ↓                                 ↓//      --------   --------   --------     --------   --------   --------//      | next |-->| next |-->| next |     | next |-->| next |-->| next |//  ... --------   --------   -------- ... --------   --------   -------- ...//      | prev |<--| prev |<--| prev |     | prev |<--| prev |<--| prev |//      --------   --------   --------     --------   --------   --------////                           position//                               ↓//      --------   --------   --------   --------   --------   --------//      | next |-->| next |-->| next |-->| next |-->| next |-->| next |//  ... --------   --------   --------   --------   --------   -------- ...//      | prev |<--| prev |<--| prev |<--| prev |<--| prev |<--| prev |//      --------   --------   --------   --------   --------   --------//// 操作完成后状态//                           first//                             |//               --------------|--------------------------------------//               | ------------|------------------------------------ |   last//               | |           ↓                                   | |     ↓//      -------- | |        --------   --------     --------       | |  --------   --------//      | next |-- |  ----->| next |-->| next |     | next |-----  | -->| next |-->| next |//  ... --------   |  |     --------   -------- ... --------    |  |    --------   -------- ...//      | prev |<---  |  ---| prev |<--| prev |     | prev |<-- |  -----| prev |<--| prev |//      --------      |  |  --------   --------     --------  | |       --------   --------//                    |  |                                    | |//                    |  ------                               | |//                    ------- |  ------------------------------ |//                          | |  |                              |//                          | |  |  -----------------------------//                          | |  |  |//                          | |  |  |  position//                          | |  |  |     ↓//      --------   -------- | |  |  |  --------   --------   --------   --------//      | next |-->| next |-- |  |  -->| next |-->| next |-->| next |-->| next |//  ... --------   --------   |  |     --------   --------   --------   -------- ...//      | prev |<--| prev |<---  ------| prev |<--| prev |<--| prev |<--| prev |//      --------   --------            --------   --------   --------   --------void transfer(iterator position, iterator first, iterator last){if (position != last)   // 如果last == position, 则相当于链表不变化, 不进行操作{(*(link_type((*last.node).prev))).next = position.node;(*(link_type((*first.node).prev))).next = last.node;(*(link_type((*position.node).prev))).next = first.node;link_type tmp = link_type((*position.node).prev);(*position.node).prev = (*last.node).prev;(*last.node).prev = (*first.node).prev;(*first.node).prev = tmp;}}public:// 将链表x移动到position所指位置之前void splice(iterator position, list& x){if (!x.empty())transfer(position, x.begin(), x.end());}// 将链表中i指向的内容移动到position之前void splice(iterator position, list&, iterator i){iterator j = i;++j;if (position == i || position == j) return;transfer(position, i, j);}// 将[first, last}元素移动到position之前void splice(iterator position, list&, iterator first, iterator last){if (first != last)transfer(position, first, last);}void remove(const T& value);void unique();void merge(list& x);void reverse();void sort();};// 销毁所有结点, 将链表置空
template <class T, class Alloc>
void list<T, Alloc>::clear()
{link_type cur = (link_type) node->next;while (cur != node){link_type tmp = cur;cur = (link_type) cur->next;destroy_node(tmp);}// 恢复node原始状态node->next = node;node->prev = node;
}// 链表赋值操作
// 如果当前容器元素少于x容器, 则析构多余元素,
// 否则将调用insert插入x中剩余的元素
template <class T, class Alloc>
list<T, Alloc>& list<T, Alloc>::operator=(const list<T, Alloc>& x)
{if (this != &x){iterator first1 = begin();iterator last1 = end();const_iterator first2 = x.begin();const_iterator last2 = x.end();while (first1 != last1 && first2 != last2) *first1++ = *first2++;if (first2 == last2)erase(first1, last1);elseinsert(last1, first2, last2);}return *this;
}// 移除容器内所有的相邻的重复结点
// 时间复杂度O(n)
// 用户自定义数据类型需要提供operator ==()重载
template <class T, class Alloc>
void list<T, Alloc>::unique()
{iterator first = begin();iterator last = end();if (first == last) return;iterator next = first;while (++next != last){if (*first == *next)erase(next);elsefirst = next;next = first;}
}// 假设当前容器和x都已序, 保证两容器合并后仍然有序
template <class T, class Alloc>
void list<T, Alloc>::merge(list<T, Alloc>& x)
{iterator first1 = begin();iterator last1 = end();iterator first2 = x.begin();iterator last2 = x.end();// 注意:前提是,两个lists都已经递增排序while (first1 != last1 && first2 != last2)if (*first2 < *first1){iterator next = first2;transfer(first1, first2, ++next);first2 = next;}else++first1;if (first2 != last2)transfer(last1, first2, last2);
}

STL源码剖析---list相关推荐

  1. STL源码剖析学习七:stack和queue

    STL源码剖析学习七:stack和queue stack是一种先进后出的数据结构,只有一个出口. 允许新增.删除.获取最顶端的元素,没有任何办法可以存取其他元素,不允许有遍历行为. 缺省情况下用deq ...

  2. 《STL源码剖析》学习-- 1.9-- 可能令你困惑的C++语法1

    最近在看侯捷的<STL源码剖析>,虽然感觉自己c++看得比较深一点,还是感觉还多东西不是那么明白,这里将一些细小的东西或者概念记录一下. 有些东西是根据<C++编程思想>理解的 ...

  3. 《STL源码剖析》学习--6章--_rotate算法分析

     最近在看侯捷的<STL源码剖析>,其中有许多不太明白之处,后经分析或查找资料有了些理解,现记录一下. <STL源码剖析>学习--6章--random access ite ...

  4. 《STL源码剖析》学习--6章--power算法分析

    最近在看侯捷的<STL源码剖析>,其中有许多不太明白之处,后经分析或查找资料有了些理解,现记录一下. 6章--power算法分析 书本中的算法如下所示: template <clas ...

  5. STL源码剖析——P142关于list::sort函数

    在list容器中,由于容器自身组织数据的特殊性,所以list提供了自己的排序函数list::sort, 并且实现得相当巧妙,不过<STL源码剖析>的原文中,我有些许疑问,对于该排序算法,侯 ...

  6. STL源码剖析---红黑树原理详解下

    转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7760584       算法导论书上给出的红黑树的性质如下,跟STL源码 ...

  7. STL源码剖析面试问题

    当vector的内存用完了,它是如何动态扩展内存的?它是怎么释放内存的?用clear可以释放掉内存吗?是不是线程安全的? vector内存用完了,会以当前size大小重新申请2* size的内存,然后 ...

  8. STL源码剖析学习二:空间配置器(allocator)

    STL源码剖析学习二:空间配置器(allocator) 标准接口: vlaue_type pointer const_pointer reference const_reference size_ty ...

  9. STL源码剖析 数值算法 copy 算法

    copy复制操作,其操作通过使用assignment operator .针对使用trivial assignment operator的元素型别可以直接使用内存直接复制行为(使用C函数 memove ...

  10. STL源码剖析 算法开篇

    STL源码剖析 算法章节 算法总览_CHYabc123456hh的博客-CSDN博客 质变算法 质变算法 - 会改变操作对象的数值,比如互换.替换.填写.删除.排列组合.分隔.随机重排.排序等 #in ...

最新文章

  1. 关于php socket客户端连接java socket服务器端,出现连接中断的问题。
  2. BAT可真拿抖音一点儿办法也没有
  3. java鼠标进入高亮效果_鼠标选中文本划词高亮、再次选中划词取消高亮效果
  4. 深度学习之迁移学习实现神奇宝贝识别
  5. [html] websocket和socket有什么区别?
  6. (25)System Verilog类外约束类内变量
  7. 由于芯片短缺 现代汽车牙山工厂将再度停产
  8. 来面试,偷懒不答题,直接忽略
  9. user32.dll 函数说明小结
  10. 简单C语言小程序:求根公式求一元二次方程式的根!
  11. 二重积分的复化Simpson方法
  12. 【esp32-s3】6.2 文件系统——文件夹列表
  13. android root后手机文件管理器,Android超强文件管理器:Root Explorer
  14. java内存溢出定位
  15. 便携电源快充方案 30W自动升降压PD快充
  16. 设置canvas画布大小
  17. PBOC/EMV之文件结构
  18. sqlplus连接到远程数据库
  19. ORM一键还原系统官方版
  20. Apache Iceberg 数据湖从入门到放弃(2) —— 初步入门

热门文章

  1. 前沿分享|阿里云数据库解决方案资深专家 李圣陶:云原生数据库解决方案 加速企业国产化升级
  2. 阿里云携手晞司盖工业,赋能设备制造商制造+服务转型升级
  3. 第三届Apache Flink 极客挑战赛暨AAIG CUP攻略发布!
  4. 重磅 | 20+技术大咖齐聚 阿里云数据库创新上云峰会进入一周倒计时
  5. ITNEXT :“这个项目可能会改变我们使用 Kubernetes 的方式”
  6. 2021研发效能实践案例征集大赛
  7. 对待棘手bug,新手与大牛的差距在哪里?
  8. Java面试题 String类能不能被继承?为什么?
  9. SQL基础【六、and与or】
  10. 【MySQL】计算 TPS,QPS 的方式