stl中list复现

 节点的结构体

首先节点先套用一个模版,因为数据的数据类型可能是各种各样的自定义类型,或者是内置类型的

成员变量

一个data存储数据,next节点指向下一个节点,prev指向前一个节点,

构造函数

传一个T数据类型的x,其中x可能是任何数据类型的,可以不填值,只开空间,next和prev都是指向的空

 template<class T>
    struct list_node{
        T _data;
        list_node<T>* _next;
        list_node<T>* _prev;
        list_node(const T& x=T())
        :_data(x),
        _next(nullptr),
        _prev(nullptr)
        {}
    };

迭代器

list的迭代器和string,vector的不同,string,vector的的数据存储是在连续的空间里面,而list需要用链接的地址去迭代,所以最好就是封装出一个迭代器去模拟指针的行走过程

模版

这边模版包含类型,ref代表引用该参数,Ptr代表指针

 template<class T, class Ref, class Ptr>

定义类型

第一个数据类型是将list_node简写成Node,第二个是将该struct简写成self

struct _list_iterator{
       typedef list_node<T> Node;
       typedef  _list_iterator<T,Ref,Ptr> self;

构造函数

创建一个node类型的指针的成员函数,然后我们给该结构体进行初始化列表初始化

Node* _node; 
_list_iterator(Node* node)
        :_node(node)
        {}

 operator++和operator--

++和--分别返回当前节点的下一个节点

self& operator++(){
            _node=_node->_next;
        return *this;
        }
        self& operator--(){
            _node=_node->_prev;
            return *this;
        }

operator后置++和后置--

迭代器其实已经向后走了,但是返回的却是原迭代器的地址

 self operator++(int){
            self tmp(*this);
            _node=_node->_next;
            return tmp;
        }

        self operator--(int){
            self tmp(*this);
            _node=_node->_prev;
            return tmp;
        }

operator*

返回的是该迭代器指针指向的数据

   T& operator*(){
            return _node->_data;
        }

operator==和!=

==比较两个指针是否相等,相等则为1,不相等则为0,!=反之

bool operator!=(const self& s){
            return _node!=s._node;
        }
        bool operator==(const self& s){
            return _node==s._node;
        }

 operator->

返回的是自定义或者

   T* operator->(){
            return &_node->_data;
        }

 创建一个自定义类型的struct,其中有两个成员变量a1和a2,并对其初始化

struct AA{

        AA(int a1=0,int a2=0)
        :_a1(a1),
        _a2(a2)
        {}

        int _a1;
        int _a2;
    };

 

这边->等价于.operator-> ()->,operator->()调用该函数该函数返回的是node->data的地址,该地址再解引用返回_a1

list

模版

依旧采用和iterator一样的模版

   template<class T, class Ref, class Ptr>

成员变量

一个是Node类型的节点,还有一个size记录链表长度

 Node* _head;
        size_t _size;

类型定义

我们让Node成为私有类型,因为我们不想让外部访问他,而interator和const_iterator可以进行外部访问

     typedef  list_node<T> Node;
    public:
        typedef  _list_iterator<T,T&,T* > iterator;
        typedef  _list_iterator<T,const T&,const T*>const_iterator;

成员函数

构造函数

我们在这直接调用一个初始化函数来建造链表的头节点,头节点new一个Node类型,头节点和尾节点都指向自己,size=0;

 void empty_init(){
            _head=new Node;
            _head->_next=_head;
            _head->_prev=_head;
            _size=0;
        }
        list(){
            empty_init();
        }

 

析构函数

先调用一个clear函数,clear函数中用一个迭代器去指向begin的位置,然后从该位置一直erase后链表清空,清空完后销毁head节点

 void clear(){
            iterator it=begin();
            while(it!=end()){
                it= erase(it);
            }
        }   
~list(){
            clear();
            delete _head;
            _head=nullptr;
        }

拷贝构造函数

我们先调用初始化函数建造一个头节点,建完后遍历被拷贝的链表,进行尾插

 list(list<T>& lt){
            empty_init();
            for(auto& e:lt){
                push_back(e);
            }
        }

operator=

直接调用swap函数去交换,这边等于是一个传值穿参,所以可以直接交换

 void swap(list<T>& lt){
            std::swap(lt._head,_head);
            std::swap(lt._size,_size);
        }
        list<T>& operator=(list<T> lt){
            swap(lt);
            return *this;

        }

begin和end

begin和end都是用了iterator进行返回,其中begin返回的是head下一个位置,因为是双向循环带头链表,所以end就是head节点

 iterator begin(){
            return _head->_next;
        }
        iterator end(){
            return _head;
        }

insert

     先创建cur节点指向it._node,其中it是iterator类型的指针,prev指向cur的前一个位置,我们在这个位置插入一个节点,插完后size++,返回的是把newnode强转成iterator类型指针,这个指针就是指向new node的地址,同样,返回的也是该地址。

 iterator insert(iterator it,const T& x){
            Node* cur=it._node;
            Node* prev=cur->_prev;
            Node* newnode=new Node(x);
            prev->_next=newnode;
            newnode->_prev=prev;
            cur->_prev=newnode;
            newnode->_next=cur;
            ++_size;
            return iterator(newnode);
        }

 

push_back

插入end前面的地址

 void push_back(const T& x){
           insert(end(),x);
        }

 

 push_front

头插就是在头部插入

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

 erase

创建三个迭代器分别指向前,当前,后节点,再释放当前节点后连接后返回下一个节点的迭代器指针

  iterator erase(iterator it){
            Node* cur=it._node;
            Node* prev=cur->_prev;
            Node* next=cur->_next;

            delete[] cur;
            prev->_next=next;
            next->_prev=prev;
            --_size;
          return iterator(next);
//        return next;
        }

pop_back和pop_front

分别都直接调用erase函数去进行pop

  void pop_back(){
            erase(--end());
        }
        void pop_front(){
            erase(begin());
        }

size

直接返回即可

size_t size(){
            return _size;
        }

const_iterator

可以再写一个类去封装const_iterator,但是实现的功能和iterator差不多,所以,只要在iterator的基础上略做调整

传过去的时候是const类型的,就变成只读了。

 typedef  _list_iterator<T,const T&,const T*>const_iterator;
  template<class T,class Ref,class Ptr >
 const_iterator begin()const{
            return (const_iterator)(_head->_next);
        }
        const_iterator end()const{
            return (const_iterator)(_head);
        }

 typename

list<T>未实例化模版,编译器不敢进去找,编译器不确定list<T>::const_iterator是内嵌类型还是静态成员变量
加typename告诉编译器,这是个类型,等list<T>实例化后再去类里去取

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值