• STL之list容器的实现框架


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

            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源代码剖析 侯捷》

  • 相关阅读:
    NPM
    Angular2.0快速开始
    AngularJS常用插件与指令收集
    Linq 操作基础
    SQL Server2008 with(lock)用法
    SQL Server2008 MERGE指令用法
    SQL Server2008 表旋转(pivot)技术
    ef to sqlite 实际开发问题终极解决方法
    windows控件常用缩写
    SQL 查询总结
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/7079923.html
Copyright © 2020-2023  润新知