0


STL:List从0到1

请添加图片描述

在这里插入图片描述

🎉个人名片:

🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🙈个人主页🎉:GOTXX
🐼个人WeChat:ILXOXVJE
🐼本文由GOTXX原创,首发CSDN🎉🎉🎉
🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路
🐓每日一句:如果没有特别幸运,那就请特别努力!🎉🎉🎉
————————————————

🎉文章简介:

🎉本篇文章将 介绍如何使用C++编写代码来实现一个类似于STL中的List容器 相关知识进行分享!
💕如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加 油,一起奔跑,让我们顶峰相见!!!🎉🎉🎉
——————————————————

一.前言

这篇文章将介绍如何使用C++编写代码来实现一个类似于STL中的List容器。 list是一个可以在常数范围内在任意位置进行插入和删除的序列式容器。在这篇文章中,你将学习并实现List的常见功能,如添加元素、删除元素等。通过实现自己的List容器,你将更好地熟悉List的使用及相关特性,并提升对C++语言的理解和掌握。
————————————————

二.List的介绍

List文档介绍链接: link

  1. list是一个可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代;
  2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素;
  3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效;
  4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好(不需要挪动数据);
  5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素);

三.List的结构及模拟实现

一.底层结构

List底层是一个带头双向循环链表

如图:
在这里插入图片描述
在这里插入图片描述
库里面的begin() 与end() 返回的节点位置:

begin()返回的是头节点的下一个节点;
而end()返回的是头节点;

二.List的模拟实现

重点::迭代器的实现

1. 构造函数
template<classT>structListNode{ListNode<T>(const T& x=T()):_next(nullptr),_prev(nullptr),_val(x){}
    ListNode<T>* _next;
    ListNode<T>* _prev;
    T _val;};

库里面的List类的构造函数是另写一个函数,因为这个函数拷贝构造会使用,然后复用它,所以我们也这样实现;

template<classT>classList{public:voidempty_List(){
        _phead =new node;
        _phead->_next = _phead;
        _phead->_prev = _phead;}List(){empty_List();}}
2. 拷贝构造函数
List(const List<T>& lt){empty_List();//初始化for(constauto& e : lt){push_back(e);//将lt里面的数据依次尾插}}
3. 插入函数

思路:记录前一个和后一个节点,然后连接

在这里插入图片描述

iterator insert(iterator pos,const T& x){
    node* newnode =newnode(x);//构造一个节点
    node* next = pos._node;         
    node* prev = next->_prev;//记录前一个
    newnode->_next = next;         
    next->_prev = newnode;//链接
    newnode->_prev = prev;
    prev->_next = newnode;return pos;}
4. 尾插函数

复用insert函数

voidpush_back(const T& x){/*    node* newnode = new node(x);
    node* tail = _phead->_prev;
    tail->_next = newnode;
    newnode->_prev = tail;       //不复用的写法
    newnode->_next = _phead;
    _phead->_prev = newnode;*/insert(end(), x);}
5. 头插函数

复用insert函数

voidpush_front(const T& x){insert(begin(),x);}
6. 删除函数
iterator erase(iterator pos){assert(pos!=end());

    node* prev = pos._node->_prev;//保存前一个节点
    node* next = pos._node->_next;//保存后一个节点
    prev->_next = next;//连接
    next->_prev = prev;delete pos._node;//释放掉该节点return next;//返回删除元素的下一个节点}
7. 尾删函数

复用删除函数

voidpop_back(){//erase(end()._node->_prev);erase(--end());//头节点的前指针指向的是最后一个节点}
8. 头删函数

复用删除函数

voidpop_front(){erase(begin());}
9. 迭代器的实现

因为链表的底层物理空间不是连续的,所以不能使用原生指针类实现。因为原生指针++,可以找到下一个数据,但是链表的节点与节点之间不是连续的,指针++,不能找到下一个节点,所以我们需要操作符重载,改变 ++, != ,* 等操作符的行为;又因为节点指针是内置类型,不能进行操作符重载,所以我们只能将它进行封装,封装在一个类里面,进行重载;

template<classT,classRef,classPtr>struct__List_iterator{typedef ListNode<T> node;typedef __List_iterator<T,Ref,Ptr> self;__List_iterator(node* node)//构造函数:_node(node){}
    self&operator++()//运算符的重载{
        _node = _node->_next;//前置++,返回++后的值return*this;}
    self operator++(int){
        self tmp(_node);//保存++前的值
        _node = _node->_next;return tmp;//返回++前的值}
    self&operator--(){
        _node = _node->_prev;return*this;}
    self operator--(int){
        self tmp(_node);
        _node = _node->_prev;return tmp;}
    Ref operator*(){return _node->_val;}
    Ptr operator->{return&_node->-val;}booloperator!=(const self& s){return s._node!=this->_node;}booloperator==(const self& s){return s._node ==this->_node;}
    node* _node;};
10. 赋值运算符重载

传统写法:

voidclear(){
        iterator lt =begin();while(lt !=end()){
            lt =erase(lt);}}//lt1=lt2
List<T>&operator=(const List<T>& lt){clear();//清空函数,将链表中的有效数据删除掉,保留头节点for(constauto& e : lt){push_back(e);//依次尾插}return*this;}

现代写法:

voidswap(List<T>& lt){
    std::swap(_phead, lt->_phead);}//lt1=lt2
List<T>&operator=(List<T> lt)//lt是lt2的拷贝构造{swap(lt);//交换lt与lt1return*this;//返回}
补充知识:

typedef 放在类里面与外面的区别:
如果是放在公有里面,则类外面也可以使用,但是要指定类域;
如果是私有的话,则类外面不能使用;

三.总代码:

#pragmaonce#include<iostream>#include<assert.h>usingnamespace std;namespace L
{template<classT>structListNode{ListNode<T>(const T& x=T()):_next(nullptr),_prev(nullptr),_val(x){}
        ListNode<T>* _next;
        ListNode<T>* _prev;
        T _val;};template<classT,classRef,classPtr>struct__List_iterator{typedef ListNode<T> node;typedef __List_iterator<T,Ref,Ptr> self;__List_iterator(node* node):_node(node){}
        self&operator++(){
            _node = _node->_next;return*this;}//self& operator++(int)//错误,
        self operator++(int){
            self tmp(_node);
            _node = _node->_next;return tmp;}
        self&operator--(){
            _node = _node->_prev;return*this;}
        self operator--(int){
            self tmp(_node);
            _node = _node->_prev;return tmp;}
        Ref operator*(){return _node->_val;}
        Ptr operator->(){return&_node->_val;}booloperator!=(const self& s){return s._node!=this->_node;}booloperator==(const self& s){return s._node ==this->_node;}
        node* _node;};template<classT>classList{public:typedef ListNode<T> node;typedef __List_iterator<T,T&,T*>  iterator;typedef __List_iterator<T,const T&,const T*>  const_iterator;

        iterator begin(){returniterator(_phead->_next);}
        iterator end(){returniterator(_phead);}
        const_iterator begin()const{returniterator(_phead->_next);}
        const_iterator end()const{returniterator(_phead);}voidempty_List(){
            _phead =new node;
            _phead->_next = _phead;
            _phead->_prev = _phead;}List(){empty_List();}List(const List<T>& lt){empty_List();for(constauto& e : lt)//引用更好,如果T类型是自定义类型的话{push_back(e);}}//lt1=lt2
        List<T>&operator=(const List<T>& lt){clear();for(constauto& e : lt){push_back(e);}return*this;}voidswap(List<T>& lt){
            std::swap(_phead, lt->_phead);}//lt1=lt2
        List<T>&operator=(List<T> lt){swap(lt);return*this;}voidclear(){
            iterator lt =begin();while(lt !=end()){
                lt =erase(lt);}}~List(){clear();delete _phead;
            _phead =nullptr;}voidpush_back(const T& x){/*    node* newnode = new node(x);
            node* tail = _phead->_prev;
            tail->_next = newnode;
            newnode->_prev = tail;
            newnode->_next = _phead;
            _phead->_prev = newnode;*/insert(end(), x);}voidpush_front(const T& x){insert(begin(),x);}
        iterator insert(iterator pos,const T& x){
            node* newnode =newnode(x);
            node* next = pos._node;
            node* prev = next->_prev;
            newnode->_next = next;
            next->_prev = newnode;
            newnode->_prev = prev;
            prev->_next = newnode;return pos;}
        iterator erase(iterator pos){assert(pos!=end());

            node* prev = pos._node->_prev;
            node* next = pos._node->_next;
            prev->_next = next;
            next->_prev = prev;delete pos._node;return next;}voidpop_back(){//erase(end()._node->_prev);erase(--end());}voidpop_front(){erase(begin());}private:
        node* _phead;};

请添加图片描述

标签: c++ list 开发语言

本文转载自: https://blog.csdn.net/2301_77509762/article/details/136763202
版权归原作者 GOTXX 所有, 如有侵权,请联系我们删除。

“STL:List从0到1”的评论:

还没有评论