STL: list的底层实现(下)
2026/5/9 2:03:30 网站建设 项目流程

文章目录

  • list接口函数实现
    • 前言
    • 一.插入和删除函数
      • 1.1任意位置插入函数——insert
      • 1.2任意位置删除函数——erase
      • 1.3尾插函数——push_back
      • 1.4尾删函数——push_back
      • 1.5头插函数和头删函数——push_back和pop_front
    • 二.清除函数与析构函数——clear和~list
    • 三.多种构造函数

list接口函数实现

前言

在我们上篇文章中当你看懂了在list中迭代器的创建时,就可以写下面的增删查改的函数了,因为有些函数的参数时迭代器,也是与库里的函数保持接口一致,有兴趣的小伙伴可以看看库里的list的函数这样也能方便理解代码。这是list的库里的函数: https://legacy.cplusplus.com/reference/list/list/?kw=list
我把我上篇文章实现的基本框架的代码放到这里,方便我下面代码的可读性

template<classT,classRef,classPtr>struct__list_iterator{typedef_list_node<T>node;typedef__list_iterator<T,Ref,Ptr>self;node*_node;self(node*Node):_node(Node){}Refoperator*(){return_node->data;}self&operator++(){_node=_node->_next;return*this;}self&operator++(int){selftmp(*this);_node=_node->_next;returntmp;}booloperator!=(constself&it)const{return_node!=it._node;}self&operator--(){_node=_node->_prev;return*this;}self&operator--(int){selftmp(*this);_node=_node->_prev;returntmp;}Ptroperator->(){return&_node->data;}};template<classT>classlist{public:typedef_list_node<T>node;typedef__list_iterator<T,T&,T*>iterator;typedef__list_iterator<T,constT&,constT*>const_iterator;iteratorbegin(){returniterator(_head->_next);}iteratorend(){returniterator(_head);}const_iteratorbegin()const{returnconst_iterator(_head->_next);}const_iteratorend()const{returnconst_iterator(_head);}voidempty_init(){_head=newnode;_head->_prev=_head;_head->_next=_head;}list(){empty_init();}

一.插入和删除函数

1.1任意位置插入函数——insert


观察库里的函数我们发现第一个函数就是返回迭代器类型的所以我们仿照它,这里面的类型是被typedef过的可以去list标准库里面看

iteratorinsert(iterator pos,constT&val=T()){node*cur=pos._node;node*prev=cur->_prev;node*newnode=newnode(val);newnode->_next=cur;newnode->_prev=prev;cur->_prev=newnode;prev->_next=newnode;returniterator(newnode);}

缺点:虽然说是在指定位置前面插入但是lsit的迭代器只能一个一个走,

intmain(){autoit=l1.begin();++it;insert(it,100);}

这样才能在第二个位置前面插入100,这个最大的作用就是在其他函数复用代码,比如在头插和尾插中调用这个函数就行。
注意:这个函数里面的代码很简单,返回值的话,c++是支持返回匿名对象的,或者可以直接返回newnode它会支持隐式类型转化。

1.2任意位置删除函数——erase


库里也是迭代器实现,我们就实现删除单个结点,下面删除迭代器区间的话你们下去也可以自己试试

iteratorerase(iterator pos){node*cur=pos._node;node*prev=cur->_prev;node*next=cur->_next;prev->_next=next;next->_prev=prev;deletecur;returniterator(next);

注意:完成这个删除函数之后去测试一定要小心迭代器失效,虽然我们自己写的函数发生了不会报错,全凭自己感觉,常见的会发生迭代器失效的就是扩容和删除数据,在这里删除当前的结点后,这个位置的迭代器就失效了,不能返回当前的迭代器,所以我们在erase中返回的就是下一个结点的迭代器所以我们要重新接收一下,

intmain{list<int>l1;//假如l1中存在数据autoit=l1.begin();while(it!=l1.end()){it=l1.erase(it)//重点}}}

1.3尾插函数——push_back

voidpush_back(constT&val){/* node* newnode = new node(val); node* ptail = _head->_prev; newnode->_prev = ptail; newnode->_next = _head; ptail->_next = newnode; _head->_prev = newnode;*/insert(end(),val);}

可以像我的注释掉的代码那样写,也可以直接复用刚刚写的,end()返回的是头结点,在头结点的前面插入不就是在尾部插入。

1.4尾删函数——push_back

voidpop_back(){erase(--end());}

删除尾部那不就是头结点的上一个结点,复用函数真的很爽

1.5头插函数和头删函数——push_back和pop_front

voidpush_front(constT&val){insert(begin(),val);}voidpop_front(){erase(begin());}

二.清除函数与析构函数——clear和~list

~list(){clear();delete_head;_head=nullptr;}voidclear(){autoit=begin();while(it!=end()){it=erase(it);}}

清除结点的clear函数不会把头结点删除,所以在析构函数中需要delete 头结点

三.多种构造函数

3.1拷贝构造函数

list(constlist<T>&l1){empty_init();//范围for实现for(constauto&e:l1){push_back(e);}//迭代器实现拷贝autoit=l1.begin();while(it!=l1.end()){push_back(*it);++it;}}

如果不会范围for的话可以用迭代器来实现,本质范围for在底层也是转化为迭代器

3.2初始化列表构造函数
关键字是initializer_list这是c++11后特有的类型

list(initializer_list<T>l1){empty_init();for(constauto&e:l1){push_back(e);}

有了这个类型在创建对象的时候据可以直接像数组一样的·输入数据

list<int>l1={1,2,3,4,5};

这样写l1就有五个结点并且每个结点分别对应这五个数字。

3.3多个值的构造函数

list(size_t n,constT&val=T()){empty_init();for(inti=0;i<n;++i){push_back(val);}}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询