欢迎来到我的Blog,点击关注哦💕
list的介绍和模拟实现
前言
stringvector的是存储是基于物理空间上连续的,而
list是作为线性的链式结构,是值得学习的。
list
介绍
std::list是C++标准模板库(STL)中的一个容器适配器,它内部实现为双向链表结构。- 这种设计使得
std::list能够在常数时间内进行任意位置的插入和删除操作,这是其相对于其他序列容器如std::vector的显著优点。 std::list不支持随机访问,即无法直接通过索引来访问容器中的元素,这通常需要从头部或尾部开始迭代到目标位置.
标准库容器
std::list
与
std::vector
的优缺点
- std::list: 作为一个双向链表,std::list 在插入和删除操作上具有优势,因为这些操作只涉及到改变相邻节点的指针,而不需要移动其他元素。此外,std::list 不需要预分配额外的内存,可以更好地处理动态内存分配,减少内存碎片.
- std::vector: 作为一个动态数组,std::vector 提供了高效的随机访问能力,可以通过下标直接访问任意位置的元素,其访问效率为 O(1). 此外,std::vector 通常具有较高的空间利用率和缓存友好性,因为其元素在内存中是连续存储的.
缺点
- std::list: 由于非连续的内存存储,std::list 在访问元素时效率较低,因为可能需要从头开始遍历链表。此外,每个节点都需要存储额外的指针信息,这增加了内存开销.
- std::vector: 在 std::vector 的中间位置插入或删除元素可能会引起大量元素的移动,以维持内存的连续性,这会导致较差的性能。当 std::vector 的容量不足以容纳新增元素时,还需要进行动态扩容,这是一个成本较高的操作
vectorlist底层
结构动态顺序表,一段连续空间带头结点的双向循环链表随 机
访 问支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素 效率O(N)插 入
删 除任意位置插入和删除效率低,需要搬移元素,
时间复杂度为O(N),插入时有可能需要增容,
增容:开辟新空 间,拷贝元素,释放旧空间,导致效率更低任意位置插入和删除效率高,不 需要搬移元
素,时间复杂度为 O(1)插 入
删 除底层为连续空间,不容易造成内存碎片,空间利用率 高,缓存利用率高底层节点动态开辟,小节点容易 造成内存碎片,空间利用率低, 缓存利用率低迭 代 器原生态指针对原生态指针(节点指针)进行封装迭 代 器
失 效在插入元素时,要给所有的迭代器重新赋值,因为插入 元素有可能会导致重新扩容,致使原来迭代器失效,删 除时,当前迭代器需要重新赋值否则会失效插入元素不会导致迭代器失效, 删除元素时,只会导致当前迭代 器失效,其他迭代器不受影响使 用
场 景需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随 机访问
的基本操作list
构造函数
【C++】vector介绍以及模拟实现接口说明list (size_type n, const value_type& val = value_type())构造的list中包含n个值为val的元素list()构造空的listlist (const list& x)拷贝构造函数list (InputIterator first, InputIterator last)用[first, last)区间中的元素构造list
list iterator
此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。
函数声明接口说明begin + end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器rbegin + rend返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的 reverse_iterator,即begin位置
list capcacity
函数声明接口说明empty检测list是否为空,是返回true,否则返回falsesize返回list中有效节点的个数
list modify
函数声明接口说明push_front在list首元素前插入值为val的元素pop_front删除list中第一个元素push_back在list尾部插入值为val的元素pop_back删除list中最后一个元素insert在list position 位置中插入值为val的元素erase删除list position位置的元素swap交换两个list中的元素clear清空list中的有效元素
list
模拟实现
存贮结构(双向带头循环)
- 定义一个类(C语言:结构体)存储数据,作为指向下一个上一个的节点
namespace MyList
{//LIst节点template<classT>struct_list_node{
_list_node<T>* _next;
_list_node<T>* _prev;
T _val;_list_node(const T& val =T()):_next(nullptr),_prev(nullptr),_val(val){}};}
iterator
迭代器有两种实现方式,具体应根据容器底层数据结构实现:
- 原生态指针,比如:
vector``````string - 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法: 1. 指针可以解引用,迭代器的类中必须重载operator*() 2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载 oprator->() 3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int) 4. 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()
iterator
结构
- 三个模板参数 1. 第一个模板参数控制类型2. 第二个模板参数控制返回值类型
const``````非const3. 第三个模板参数控制返回的list类的类型const``````非const Node* _node;需要定义一个指针,指向list节点
template<classT,classRef,classptr>struct_list_iterator{typedef _list_node<T> Node;typedef _list_iterator<T, Ref,ptr> self;
Node* _node;};
operator!=
operator ==
//重载operator!=booloperator!=(const self& it)const{return _node != it._node;}//重载operator==booloperator==(const self& it)const{return _node == it._node;}
operator++
//重载operator++(前置)
self&operator++(){
_node = _node->_next;return*this;}//重载operator++(后置)
self&operator++(int){
self tmp(*this);
_node = _node->_next;return tmp;}
operator--
//重载operator--(前置)
self&operator--(){
_node = _node->_prev;return*this;}//重载operator--(后置)
self&operator--(int){
self tmp(*this);
_node = _node->_prev;return tmp;}
operator*
operator->
//重载operator*
Ref&operator*(){return _node->_val;}//重载operator->
ptr operator->(){return _node->_val;}
list
数据结构
构造函数
list的初始化
- 双向带带头循环
#mermaid-svg-1LAJp6yJtxQBCAfN {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-1LAJp6yJtxQBCAfN .error-icon{fill:#552222;}#mermaid-svg-1LAJp6yJtxQBCAfN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1LAJp6yJtxQBCAfN .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-1LAJp6yJtxQBCAfN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1LAJp6yJtxQBCAfN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1LAJp6yJtxQBCAfN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1LAJp6yJtxQBCAfN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1LAJp6yJtxQBCAfN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1LAJp6yJtxQBCAfN .marker.cross{stroke:#333333;}#mermaid-svg-1LAJp6yJtxQBCAfN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1LAJp6yJtxQBCAfN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1LAJp6yJtxQBCAfN .cluster-label text{fill:#333;}#mermaid-svg-1LAJp6yJtxQBCAfN .cluster-label span{color:#333;}#mermaid-svg-1LAJp6yJtxQBCAfN .label text,#mermaid-svg-1LAJp6yJtxQBCAfN span{fill:#333;color:#333;}#mermaid-svg-1LAJp6yJtxQBCAfN .node rect,#mermaid-svg-1LAJp6yJtxQBCAfN .node circle,#mermaid-svg-1LAJp6yJtxQBCAfN .node ellipse,#mermaid-svg-1LAJp6yJtxQBCAfN .node polygon,#mermaid-svg-1LAJp6yJtxQBCAfN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1LAJp6yJtxQBCAfN .node .label{text-align:center;}#mermaid-svg-1LAJp6yJtxQBCAfN .node.clickable{cursor:pointer;}#mermaid-svg-1LAJp6yJtxQBCAfN .arrowheadPath{fill:#333333;}#mermaid-svg-1LAJp6yJtxQBCAfN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1LAJp6yJtxQBCAfN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1LAJp6yJtxQBCAfN .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-1LAJp6yJtxQBCAfN .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-1LAJp6yJtxQBCAfN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1LAJp6yJtxQBCAfN .cluster text{fill:#333;}#mermaid-svg-1LAJp6yJtxQBCAfN .cluster span{color:#333;}#mermaid-svg-1LAJp6yJtxQBCAfN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1LAJp6yJtxQBCAfN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
_head
//空list初始化voidempty_init(){
_head =new Node;
_head->_next = _head;
_head->_prev = _head;
_size =0;}
节点初始化
- 默认构造函数
- 默认构造函数
- 用迭代器初始化
- 拷贝构造函数
- 赋值运算符重载
- 赋值运算符重载
//默认构造函数list(){empty_init();}//默认构造函数list(int n,const T& val =T()){empty_init();while(n--){push_back(val);}}//用迭代器初始化template<classIterator>list(Iterator first, Iterator last){empty_init();while(first != last){push_back(*first);++first;}}//拷贝构造函数list(const list<T>& lt){empty_init();for(auto e : lt){push_back(e);}}//赋值运算符重载
list<T>operator=(list<T> lt){swap(lt);return*this;}//赋值运算符重载~list(){clear();delete _head;}
迭代器
iterator begin(){return _head->_next;}
iterator end(){return _head;}
const_iterator begin()const{return _head->_next;}
const_iterator end()const{return _head;}
list modify
insert
- 在pos位置插入节点,同数据结构是一样的,在这里面不过多赘述(可以参考)
//insert
iterator insert(iterator pos,const T& x){
Node* newcode =newNode(x);
Node* cur = pos._node;
Node* prev = cur->_prev;
prev->_next = newcode;
newcode->_prev = prev;
newcode->_next = cur;
cur->_prev = newcode;++_size;return pos;}
erase
- 删除迫使位置的节点,同样(可以参考)
//erase
iterator erase(iterator pos){assert(pos._node != _head);
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = next;
next->_prev = prev;delete cur;--_size;return next;}
头插、头删、尾插、尾删
- 可以复用
insert``````ersaeSTL标准模板库也是进行复用
// 头插voidpush_front(const T& x){insert(begin(), x);}//头删voidpop_front(){erase(begin());}//尾插voidpush_back(const T& x){insert(begin());}//尾删voidpop_back(){erase(--end());}
list operator
交换
voidswap(list<T> lt){
std::swap(_head, lt._head);
std::swap(_size, lt._size);}
clear
- 析构函数也是利用了clear
//删除voidclear(){
iterator it =begin();while(it !=end()){
it =erase(it);++it;}}
源码
#pragmaonce#include<iostream>#include<assert.h>namespace MyList
{//节点template<classT>struct_list_node{
_list_node<T>* _next;
_list_node<T>* _prev;
T _val;_list_node(const T& val =T()):_next(nullptr),_prev(nullptr),_val(val){}};//迭代器template<classT,classRef,classptr>struct_list_iterator{typedef _list_node<T> Node;typedef _list_iterator<T, Ref,ptr> self;
Node* _node;_list_iterator(Node* node):_node(node){}//重载operator*
Ref&operator*(){return _node->_val;}//重载operator->
ptr operator->(){return _node->_val;}//重载operator++(前置)
self&operator++(){
_node = _node->_next;return*this;}//重载operator++(后置)
self&operator++(int){
self tmp(*this);
_node = _node->_next;return tmp;}//重载operator--(前置)
self&operator--(){
_node = _node->_prev;return*this;}//重载operator--(后置)
self&operator--(int){
self tmp(*this);
_node = _node->_prev;return tmp;}//重载operator!=booloperator!=(const self& it)const{return _node != it._node;}//重载operator==booloperator==(const self& it)const{return _node == it._node;}};//listtemplate<classT>classlist{typedef _list_node<T> Node;public:typedef _list_iterator<T, T&,T*> iterator;typedef _list_iterator<T,const T&,const T*> const_iterator;//空list初始化voidempty_init(){
_head =new Node;
_head->_next = _head;
_head->_prev = _head;
_size =0;}//用n个val初始化list(int n,const T& val =T()){empty_init();while(n--){push_back(val);}}//用迭代器初始化template<classIterator>list(Iterator first, Iterator last){empty_init();while(first != last){push_back(*first);++first;}}//默认构造函数list(){empty_init();}//拷贝构造函数list(const list<T>& lt){empty_init();for(auto e : lt){push_back(e);}}//赋值运算符重载
list<T>operator=(list<T> lt){swap(lt);return*this;}//析构函数~list(){clear();delete _head;}//删除voidclear(){
iterator it =begin();while(it !=end()){
it =erase(it);++it;}}//迭代器
iterator begin(){return _head->_next;}
iterator end(){return _head;}
const_iterator begin()const{return _head->_next;}
const_iterator end()const{return _head;}//void push_back(const T& x)//{// Node* newcode = new Node(x);// Node* tail = _head->_prev;// tail->_next = newcode;// newcode->_next = _head;// newcode->_prev = tail;// _head->_prev = newcode;// ++_size;//}// 头插voidpush_front(const T& x){insert(begin(), x);}//头删voidpop_front(){erase(begin());}//尾插voidpush_back(const T& x){insert(begin());}//尾删voidpop_back(){erase(--end());}//insert
iterator insert(iterator pos,const T& x){assert(pos._node != _head);
Node* newcode =newNode(x);
Node* cur = pos._node;
Node* prev = cur->_prev;
prev->_next = newcode;
newcode->_prev = prev;
newcode->_next = cur;
cur->_prev = newcode;++_size;return pos;}//erase
iterator erase(iterator pos){assert(pos._node != _head);
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = next;
next->_prev = prev;delete cur;--_size;return next;}//大小
size_t size()const{return _size;}//交换voidswap(list<T> lt){
std::swap(_head, lt._head);
std::swap(_size, lt._size);}private:
Node* _head;
size_t _size;};}
版权归原作者 chian-ocean 所有, 如有侵权,请联系我们删除。