C++ 全栈知识体系C++ 全栈知识体系
✿导航
  • 基础
  • 函数
  • 知识点
  • IO框架
  • 新版本特性
  • 数据库原理
  • SQL语言
  • SQL - MySQL
  • NoSQL - Redis
  • NoSQL - ElasticSearch
  • 算法基础
  • 常见算法
  • 领域算法
  • 分布式算法
  • 数据结构与算法
  • 计算机网络
  • 操作系统
  • 计算机组成
  • 开发
  • 测试
  • 架构基础
  • 分布式系统
  • 微服务
  • 中间件
  • 概念
  • 理论
  • 架构设计原则
  • 设计模式
  • 协议
  • 技术选型
  • 编码规范
  • 流水线构建 - CI/CD
  • 知识点 - Linux
  • 网站 - Nginx
  • 容器化 - Docker
  • 容器编排 - Kubernetes
  • 服务网格 - Service Mesh Istio
  • 常用快捷键 - Shortcut
  • 工具使用 - Tools
  • 开源项目
  • 学习项目
  • 个人项目
  • 项目开发
  • 项目Idea
  • 并发
  • 部署
  • 分布式
  • 知识
  • 问题
  • 编程语言与技术
  • 系统与架构
  • 软件开发实践
  • 数据处理与应用设计
  • 个人
  • 产品
  • 团队
  • 知识体系
  • Vue
关于
✿导航
  • 基础
  • 函数
  • 知识点
  • IO框架
  • 新版本特性
  • 数据库原理
  • SQL语言
  • SQL - MySQL
  • NoSQL - Redis
  • NoSQL - ElasticSearch
  • 算法基础
  • 常见算法
  • 领域算法
  • 分布式算法
  • 数据结构与算法
  • 计算机网络
  • 操作系统
  • 计算机组成
  • 开发
  • 测试
  • 架构基础
  • 分布式系统
  • 微服务
  • 中间件
  • 概念
  • 理论
  • 架构设计原则
  • 设计模式
  • 协议
  • 技术选型
  • 编码规范
  • 流水线构建 - CI/CD
  • 知识点 - Linux
  • 网站 - Nginx
  • 容器化 - Docker
  • 容器编排 - Kubernetes
  • 服务网格 - Service Mesh Istio
  • 常用快捷键 - Shortcut
  • 工具使用 - Tools
  • 开源项目
  • 学习项目
  • 个人项目
  • 项目开发
  • 项目Idea
  • 并发
  • 部署
  • 分布式
  • 知识
  • 问题
  • 编程语言与技术
  • 系统与架构
  • 软件开发实践
  • 数据处理与应用设计
  • 个人
  • 产品
  • 团队
  • 知识体系
  • Vue
关于
  • 编程语言与技术

    • Effective C++: 改善程序与设计的55个具体做法

      • 第2章 - 构造/析构/赋值运算(一)
      • 第2章 - 构造/析构/赋值运算(二)
      • 第2章 - 构造/析构/赋值运算(三)
      • 第3章 - 资源管理
      • 第4章 - 设计与声明(一)
      • 第4章 - 设计与声明(二)
      • 第5章 - 实现(一)
      • 第5章 - 实现(二)
      • 第6章 - 继承与面向对象设计
      • 第7章 - 模板与泛型编程
    • 深度探索C++对象模型

      • 第1章 - 关于对象
      • 第2章 - 构造函数语意学
      • 第3章 - Data 语意学
    • STL源码剖析

      • 第1章 - STL概论和版本简介
      • 第2章 - 空间配置器
      • 第3章 - 迭代器(iterators)概念与traits编程技法(一)
      • 第3章 - 迭代器(iterators)概念与traits编程技法(二)
      • 第4章 - 序列式容器 vector
      • 第4章 - 序列式容器 list
      • 第4章 - 序列式容器 deque
      • 第4章 - 序列式容器 stack和queue
      • 第4章 - 序列式容器 heap
      • 第4章 - 序列式容器 priority_queue
      • 第4章 - 序列式容器 slist
      • 第5章 - 关联式容器 RB-tree
      • 第5章 - 关联式容器 set和map
      • 第5章 - 关联式容器 hashtable
      • 第6章 - 算法
      • 第6章 - 算法之set
      • 第7章 - 仿函数
      • 第8章 - 配接器
  • 系统与架构

    • 深入理解计算机系统

      • 第1章 - 计算机系统漫游
      • 第2章 - 信息的表示和处理
      • 第3章 - 程序的机器级表示
      • 第5章 - 优化程序性能
      • 第6章 - 存储器层次结构
      • 第7章 - 链接
      • 第8章 - 异常控制流
      • 第9章 - 虚拟内存
      • 第10章 - 系统级I/O
      • 第11章 - 网络编程
      • 第12章 - 并发编程
    • 大型网站技术架构——核心原理与案例分析

      • 第1章 - 大型网站架构演化
      • 第2章 - 大型网站架构模式
      • 第3章 - 大型网站核心架构要素
      • 第4章 - 瞬时响应:网站的高性能架构
      • 第5章 - 万无一失:网站的高可用架构
      • 第6章 - 永无止境:网站的伸缩性架构
      • 第7章 - 随需应变:网站的可扩展架构
      • 第8章 - 固若金汤:网站的安全架构
    • 从零开始学架构

      • 架构基础
      • 架构设计原则
      • 高性能架构
      • 高可用架构
    • 程序员的自我修养————链接、装载与库

      • 第1章 - 简介
      • 第2章 - 静态链路
      • 第3章 - 目标文件里有什么
      • 第4章 - 静态链接
      • 第7章 - 动态链接
      • 第8章 - 共享库版本
      • 第10章 - 内存
      • 第11章 - 运行库
      • 第12章 - 系统调用与API
      • 第13章 - 运行库实现
  • 软件开发实践

    • 重构改善既有代码的设计

      • 第1章 - 重构,第一个示例
      • 第2章 - 重构的原则
      • 第3章 - 代码的坏味道
      • 第5章 - 重构列表
      • 第6章 - 重新组织函数
      • 第7章 - 在对象之间搬移特性
      • 第8章 - 重新组织数据
      • 第9章 - 简化条件表达式
      • 第10章 - 简化函数调用
      • 第11章 - 处理概括关系
      • 第12章 - 设计之大型重构
    • 代码大全2

      • 第1章 - 欢迎进入软件构建的世界
      • 第2章 - 用隐喻来更充分地理解软件开发
      • 第3章 - 三思而后行: 前期准备
      • 第4章 - 关键的构建决策
      • 第5章 - 软件构建中的设计
    • Linux多线程服务端编程——使用muduo C++ 网络库

      • Buffer类的设计
      • 设计与实现
      • 定时器与TimerQueue
      • Protobuf网络传输和Protobuf编解码器与消息分发器
      • EventLoop类剖析
      • EventLoopThread和EventLoopThreadPool剖析
      • TCP网络库和核心类
      • Connector剖析
      • TcpClient剖析
      • 学习总结
      • timing wheel
      • 消息广播服务
      • 线程安全的对象生命期管理
  • 数据处理与应用设计

    • 数据密集型应用系统设计

      • 第1章 - 可靠、可扩展与可维护的应用系统
      • 第2章 - 数据模型与查询语言
      • 第3章 - 数据存储与检索
      • 第4章 - 数据编码与演化
      • 第5章 - 数据复制
      • 第6章 - 数据分区
      • 第7章 - 事务

第4章:序列式容器 list

    list概述

    相比于vector的连续线性空间,list显得更为复杂;**但list每次插入或删除一个元素时,就将配置或释放一个元素。**因此,list对于空间的运用有绝对的精准,一点也不浪费。对于任何位置的插入或元素删除,list永远是常数时间。

    list的节点

    下面是STL list的节点结构,显然是一个双向链表。

    template <class T>
    struct __list_node {
    	typedef void* void_pointer; 
    	void_pointer prev; //型别为void*,其实可设为__list_node<T>*
    	void_pointer next;
    	T data;
    };
    

    list的迭代器

    • list中的元素由于都是节点,因此其迭代器递增时取用的是下一个节点,递减时取用上一个节点,取值时取的是节点的数据值,成员存取时取用的是节点的成员;
    • 由于list是双向链表,迭代器必须具备前移、后移的能力,因此,list提供的是Bidirectional Iterators;
    • list的插入和接合操作都不会导致原有迭代器失效,但vector的插入可能造成存储空间重新分配,导致原有的迭代器全部失效。

    list节点和list迭代器

    reference operator*() const { return (*node).data; }//取结点数据值
     
    pointer operator->() const { return &(operator*()); }//成员存取
    
    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;
    }
    selfoperator--(int) { //运算符后置--的重载
       self tmp = *this;
       --*this;
       return tmp;
    }
    

    list的数据结构

    SGI list是一个双向链表,而且是一个环状双向链表:

    template<class T,class Alloc = alloc> //缺省使用alloc为配置器:w
    class list{
    protected :
    	typedef	__list_node<T> list_node ;
    public  :
    	typedef	list_node* link_type ;
    protected :
    	link_type node ; //只要一个指针,便可以表示整个环状双向链表
    };
    

    如果让指针 node 指向刻意置于尾端的一个空白节点, node 便能符合 STL 对于“前闭后开”区间的要求,成为 last 迭代器。

    //取首元素,node是尾端的一个空节点
    iterator begin()  {  return  (link_type) ((*node).next); }
    //取尾元素的下一个,即node
    iterator end()     {  return node;  }
    //为空,说明只有node
    bool empty() const  {  return node->next == node; }
    size_type size()  const {
    	size_type result = 0;
    	distance(begin(), end(), result);
    	return result;
    }
    reference front()    { return *begin(); }
    reference back()    {  return *(--end());  }
    

    list示意图

    list的构造与内存管理

    list采用list_node_allocator来配置节点空间,以下四个函数分别用来配置、释放、构造、销毁一个节点。

    template<class T,class Alloc = alloc> //缺省使用alloc为配置器:w
    class list{
    protected :
    	typedef	__list_node<T> list_node ;
        //专属之空间配置器,每次配置一个节点大小
    	typedef	simple_alloc<list_node,Alloc> list_node_allocator;
        ...
    };
    
    //既然说到配置空间,就将配置、释放、构造、销毁一并提了吧
    //配置一个节点
    link_type get_node() 	{ return list_node_allocator::allocate(); }  
    //释放一个节点
    void put_node(link_type p)	{ list_node_deallocator::deallocate(p); }
    //产生一个节点,带有元素值
    link_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);
    }
    

    list提供了默认的构造函数,使得可以创建一个空list:

    public:
    	list()   {  empty_initialize();  }   //默认构造函数
    protected:
    	void empty_initialize() {
    		node = get_node();       //配置一个节点空间
    		node->next = node;
    		node->prev = node;
    	}
    

    list元素操作

    insert()是一个重载函数,最简单的一种如下:

    iterator insert(iterator position, const T& x){//在迭代器position所指位置插入一个节点,内容为x
    	link_type tmp = create_node(x);
    	tmp->next = position.node;
    	tmp->prev = position.node->node;
    	(link_type(position.node->prev))->next = tmp;
        position.node->prev =tmp;
    	return tmp;
    }
    

    push_front() 函数:将新元素插入于list头端,内部调用insert()函数。

    void push_front(const T&x)  { insert(begin(),x); }
    

    push_back()函数:将新元素插入于list尾端,内部调用insert()函数。

    void push_back(const T& x)   {  insert(end(),x); }
     erase() 函数:移除迭代器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);
    }
    

    pop_front()函数:移除头结点,内部调用erase()函数。

    void pop_front()  {  erase(begin());  }
    pop_back() 函数:移除尾结点,内部调用erase()函数。
    
    void pop_back(){
    iterator i=end();
    erase(--i);
    }
    

    clear()函数:清除所有节点:

    template <class T, class Alloc>  
    void list<T, Alloc>::clear()  
    {  
      link_type cur = (link_type) node->next;//node原来指向list的end,node->next为begin  
      while (cur != node)  
      {  
        link_type tmp = cur;  
        cur = (link_type) cur->next;  
        destroy_node(tmp);  
      }  
      // 恢复node原始状态  
      node->next = node;  
      node->prev = node;  
    }  
    

    transfer()迁移函数:将[ frirst , last ) 内所有元素移动到position之前。

    void transfer(iterator position, iterator first, iterator last) {
        if (position != last) {
          (*(link_type((*last.node).prev))).next = position.node; //(1)
          (*(link_type((*first.node).prev))).next = last.node;    //(2)
          (*(link_type((*position.node).prev))).next = first.node;//(3)
          link_type tmp = link_type((*position.node).prev);       //(4)
          (*position.node).prev = (*last.node).prev;              //(5)
          (*last.node).prev = (*first.node).prev;                 //(6)
          (*first.node).prev = tmp;                               //(7)
        }
      }
    

    list-transfer

    splice结合操作:

    int iv[5] = { 5,6,7,8,9 };
    list<int> ilist2(iv,iv+5);
    
    //目前,ilist的内容为 0 2 99 3 4
    ite = find(ilist.begin(),ilist.end(),99);
    ilist.splice(ite,ilist2);  // 0 2 5 6 7 8 9 99 3 4
    ilist.reverse();           // 4 3 99 9 8 7 6 5 2 0
    ilist.sort();              // 0 2 3 4 5 6 7 8 9 99
    
    // 将链表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);  
    }  
    
    Last Updated:
    Contributors: klc407073648
    Prev
    第4章 - 序列式容器 vector
    Next
    第4章 - 序列式容器 deque