说明:本文仅供学习交流,转载请标明出处。欢迎转载!

list的底层採用数据结构是环形的双向链表。 相对于vector容器。list容器插入和删除操作付出的代价要比vector容器小得多,可是list带有链表的天生弱点。就是不支持随机訪问。

从内置的迭代器角度分析。vector容器相应的迭代器为随机訪问迭代器,而list容器内置的迭代器则为双向迭代器。

我们也知道,STL中提供的非常多算法都是基于随机訪问迭代器的,如sort(b,e)函数,其所使用的迭代器就是随机訪问迭代器。所以。list不能使用这类算法函数。为此。STL又在list容器中内置了其特有的算法。这些算法都是依据list容器的特点定身制造的。

所以,要设计一个list容器,我们须要考虑这些问题:

(1)结点设计。学过数据结构的都知道。链表就是将一个一个 的结点通过指针链接起来,结点是构成链表的元素。所以首先得考虑双链表结点的设计。相应的设计代码框架例如以下:

<pre name="code" class="cpp">/********底层结点的定义**********/
template<class T>
struct _list_node
{
typedef _list_node<T> node_type;//指向本类结点的指针
node_type *pre;//前驱指针
node_type *next;//后继指针
T data;
};


(2)迭代器的设计。因为list容器相应的迭代器是双向迭代器,既然是双向迭代器,我们就必须为该迭代器提供++、--操作。而又因为链表并不一定是连续的空间分配,所以不能直接对原生的指针做++、--的操作。而应该利用迭代器对原生指针做封装。然后对迭代器重载++、--的操作,当中迭代器的++相应原生指针的p=p->next,迭代器的--则相应原生指针的p=p->pre。

/*******list迭代器的定义**********/
template<class T,class Ref=T &, class Ptr=T*>
struct _list_iterator
{
typedef _list_node<T>* link_type;//指向底层结点的指针类型
link_type p;//p表示一个原生指针。迭代器是一个智能指针,是对p的一个包装 /******以下定义迭代器的一个经常使用属性*******/
typedef T value_type;//元素类型
typedef Ptr pointer;//指针类型
typedef Ref reference;//引用类型
typedef ptrdiff_t difference_type;//指针差值类型
typedef bidirectional_iterator_tag iterator_category;//标记类型,属于双向迭代器,不支持随机訪问
typedef size_t size_type;//大小类型 /******以下定义一个智能指针的经常使用操作**********/
typedef _list_iterator<T,T&,T*> iterator_type;//名字太长了,给迭代器类定义一个别名 _list_iterator(){}//无參构造函数
_list_iterator(link_type p1):p(p1){};//单形參构造函数,參数为原生指针
_list_iterator(const iterator_type & iter):p(iter.p){};//复制构造函数 bool operator==(iterator_type& iter)const;//推断两个迭代器的原生指针是否相等,即this->p是否等于iter.p
bool operator!=(iterator_type& iter)const;//跟上相反 reference operator*()const;//解引用,返回p->data
pointer operator->()const;//箭头操作符。返回&(p->data) /******以下定义作为一个双向容器的应有操作********/
iterator_type operator++();//定义++前置操作,++iter
iterator_type operator++(int);//定义++后置操作,iter--
iterator_type operator--();//定义--前置操作,--iter
iterator_type operator--(int);//定义--后置操作,iter--
};

(3)list容器的设计。

list容器除了内部封装一个特殊的迭代器外,还须要提供一些特定算法,由于list容器的对象非常多STL提供的算法都不能使用。所以须要其自身提供封装好对应的函数。

/***************list容器的定义*************************/
template<class T,class Alloc=alloc>
class list
{
protected:
typedef _list_node<T> node_type;//定义底层结点类型别名
typedef _list_node<T>* link_type;//连接底层结点的指针类型别名
typedef simple_alloc<Node_type,Alloc> node_allocator;//定义结点空间分配器类
Node_type empty_Node;//定义一个带空节点值的结点
void init();//创建一个空环形双向链表
public:
/**************定义公有訪问属性****************/
typedef T value_type;//底层结点内含的data所相应的数据类型
typedef value_type* pointer;//指针类型
typedef value_type& reference;//引用类型
typedef ptrdiff_t difference_type;//迭代器差值类型
typedef size_t size_type;//大小类型
typedef _list_iterator<T,T&,T*> iterator;//迭代器类型
typedef const iterator const_iterator;//指向常量的迭代器类型 /*************构造函数/析构函数**************/
list();//无參构造函数,仅调用init()来初始化链表
list(InputIterator b,InputIterator e);//用[b,e)去初始化容器
list(size_type n);//创建一个含有n个元素的容器
list(size_type n,const T &t);//用n个值为t的元素去创建容器
~list();//析构函数 /*************插入操作********************/
void push_back(const T & t);//后插入
void push_front(const T & t);//前插入
iterator insert(interator iter,const T &t);//在iter前插入值t的元素,返回新加入元素的迭代器
void insert(iterator iter,size_type n,const T &t);//在iter前插入n个值为t的元素
void insert(iterator iter,iterator b,iterator e);//在iter前插入[b,e)范围的元素 /***********删除操作*********************/
iterator erase(iterator iter);//删除iter所指向的元素,返回所删除元素的下一个元素相应的迭代器
iterator erase(iterator b,iterator e);//删除[b,e)范围内的元素,返回原先e
void clear();//删除容器内的全部元素
void pop_back();//删除容器内最后一个有效的元素
void pop_front();//删除容器内第一个有效的元素 /***********大小操作*********************/
size_type size()const;//返回容器内元素的个数
size_type max_size()const;//返回容器可容纳的最多元素的个数
bool empty()const;//推断容器是否为空
void resize(size_type n);//将容器的大小设置为n
void resize(size_type n,T t);//将容器的大小设置为n。若须要须要新加入新的元素之,则其值为t /***********訪问操作*******************/
iterator begin();//返回头指针
iterator end();//返回末端元素的下一个位置
iterator rbegin();//返回最后一个元素
iterator rend();//返回头指针的前一个位置
reference front();//返回第一个元素的引用
reference back();//返回最后一个元素的引用 /**********list特有的算法操作************/
void remove(const T& t);//删除之为t的元素
void remove_if(bool preFun);//将满足特定条件的值删除
void unique();//将容器中反复的元素删除,仅仅留下第一次出现的那个元素集
void unique(bool preFun);//将满足条件的反复值删除
void reverse();//将容器的元素逆转。通过依次将尾部的元素剪切插入到首部
void sort();//将容器内的元素排序。内部是採用归并排序
/////使用merge函数必须保证连个list是有序的。否则会执行时出错,默觉得升序,也能够自定义降序///////////////
typedef list<T,alloc> List;//定义本类的类型别名,太长了
void merge(List &list2);//将list2中的元素剪切后再归并待本链表,升序
void merge(List &list2,int cmp);//将list归并到本链表,cmp指定排序方式
void splice(iterator iter,List list2);//将list2的元素剪切到本链表中的iter之前。注意:list2不同于*this
void splice (iterator iter,List & list2,iterator iter2);//将list2中iter2指向的那一个元素(仅仅有1个哈)剪切到本链表的iter之前,list2能够等于*this
void splice(iterator iter,List & list2,iterator b,iterator e);//将list2中的[b,e)内的元素剪切到本链表的iter之前,list能够等于*this
};

上面的代码中,指的一提是sort函数。该sort函数採用的是归并排序的非递归算法,还有就是reverse函数。reverse函数的实现思路是将原链表中的结点从头到尾依次剪切到头部,这样就能够将链表逆转。

參考文献

[1]《C++primer 第4版》

[2]《STL源代码剖析 侯捷》

STL之list容器的实现框架的更多相关文章

  1. STL之vector容器的实现框架

    说明:本文仅供学习交流,转载请标明出处,欢迎转载. 实现vector容器的思路等同于实现一个动态数组,以下我们參照源代码的相关资料,给出一个vector容器的大致框架,仅仅有声明,没给出详细的实现. ...

  2. C++ STL之list容器的基本操作

    由于list和vector同属于序列式容器,有很多相同的地方,而上一篇中已经写了vector,所以这一篇着重写list和vector的不同之处和特有之处. 特别注意的地方: (1)STL中迭代器容器中 ...

  3. 【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)

    文件夹      [SSH进阶之路]一步步重构容器实现Spring框架--从一个简单的容器開始(八)      [SSH进阶之路]一步步重构容器实现Spring框架--解决容器对组件的"侵入 ...

  4. 带你深入理解STL之Vector容器

    C++内置了数组的类型,在使用数组的时候,必须指定数组的长度,一旦配置了就不能改变了,通常我们的做法是:尽量配置一个大的空间,以免不够用,这样做的缺点是比较浪费空间,预估空间不当会引起很多不便. ST ...

  5. STL中的容器介绍

    STL中的容器主要包括序列容器.关联容器.无序关联容器等. 一]序列容器 (1) vector vector 是数组的一种类表示,提供自动管理内存的功能,除非其他类型容器有更好满足程序的要求,否则,我 ...

  6. STL序列式容器学习总结

    STL序列式容器学习总结 参考资料:<STL源码剖析> 参考网址: Vector: http://www.cnblogs.com/zhonghuasong/p/5975979.html L ...

  7. STL——关联式容器

    一.关联式容器 标准的STL关联式容器分为set(集合)/map(映射表)两大类,以及这两大类的衍生体multiset(多键集合)和 multimap(多键映射表).这些容器的底层机制均以RB-tre ...

  8. STL——序列式容器

    一.容器概述与分类 1. STL容器即是将运用最广的一些数据结构实现出来.常用的数据结构有array, list, tree, stack, queue, hash table, set, map…… ...

  9. C++标准模板库(STL)和容器

    1.什么是标准模板库(STL)? (1)C++标准模板库与C++标准库的关系 C++标准模板库其实属于C++标准库的一部分,C++标准模板库主要是定义了标准模板的定义与声明,而这些模板主要都是 类模板 ...

随机推荐

  1. Node.js CVE-2017-1484复现(详细步骤)

    0x00 前言 早上看Sec-news安全文摘的时候,发现腾讯安全应急响应中心发表了一篇文章,Node.js CVE-2017-14849 漏洞分析(https://security.tencent. ...

  2. Oracle-2 - :超级适合初学者的入门级笔记--定义更改约束,视图,序列,索引,同义词

    接着我上一篇的写,在这感觉到哇 内容好多啊   上一篇,纯手打滴,希望给个赞! 添加约束的语法: 使用 alter table 添加或删除约束,但是不能修改约束 有效化或无效化约束 添加not nul ...

  3. day3--远程链接Linux

    互联网上的计算机,都会有一个唯一的32位的地址,IP地址 我们访问服务器,就必须通过这个IP地址 局域网里也有预留的IP地址,192/10/172开头.局域网的IP地址也是唯一的. NAT模式,电脑宿 ...

  4. IntelliJ配置jenkins服务的Crumb Data

    近期在做jenkins测试,IntelliJ并没有自动安装jenkins服务器,因此需要自己添加,但是如果不配置Crumb Data,jenkins的服务就不能使用. 首先在服务器中开启CSRF服务, ...

  5. 运维必须掌握的150个Linux命令

    线上查询及帮助命令(1个)man 目录操作命令(6个)ls tree pwd mkdir rmdir cd 文件操作命令(7个)touch cp mv rm ln find rename 文件查看及处 ...

  6. 利用Pycharm本地调试spark-streaming(包含kafka和zookeeper等操作)

    环境准备就不说了! 第一步:打开Pycharm,在File->Setting->Project Structure中点击Add Content Root 添加本地python调用java和 ...

  7. [转载] Redis快速入门

    转载自http://www.yiibai.com/redis/redis_quick_guide.html Redis是一个开源,先进的key-value存储,并用于构建高性能,可扩展的Web应用程序 ...

  8. 【小技巧解决大问题】使用 frp 突破阿里云主机无弹性公网 IP 不能用作 Web 服务器的限制

    背景 今年 8 月份左右,打折价买了一个阿里云主机,比平常便宜了 2000 多块.买了之后,本想作为一个博客网站的,毕竟国内的服务器访问肯定快一些.满心欢喜的下单之后,却发现 http 服务,外网怎么 ...

  9. ASP.NET MVC5+EF6+EasyUI 后台管理系统(88)-Excel导入和导出-自定义表模导出

    前言 之前说了导入和导出,也提供了自定义的表模的导入,可见LinqToExcel可以做的事情不仅仅如此 这次我们来演示比较复杂的导出Excel,导出复杂的Excel与导入复杂的Excel原理基本是一样 ...

  10. 《Linux命令行与shell脚本编程大全》第十六章 控制脚本

    一些控制脚本的方式:向脚本发送信号.修改脚本优先级,在脚本运行时切换到运行模式 16.1 处理信号 linux利用信号与运行在系统中的进程进行通信. 也可以通过对脚本进行编程,使其在收到特定信号时执行 ...