【C++】list链表容器功能模拟实现

这篇具有很好参考价值的文章主要介绍了【C++】list链表容器功能模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

介绍

一,容器的结构设计

二,构造函数与赋值运算符

三,析构函数

四,list容器接口

1,begin和end

2,insert和erase

3,其它常用接口函数


介绍

        上一次介绍了list双向链表容器的迭代器模拟,这次模拟实现list的简单功能,尤其要注意构造函数、析构函数、以及赋值运算符重载的实现。这里需要进行深拷贝和确定“ 哨兵结点 ”。

        我们先回顾list迭代器的模拟结构,如下:

//结点

template<class T> //模板
struct ListNode
{
    ListNode<T>* _next;   //指向前结点的指针
    ListNode<T>* _last;  //指向后结点的指针
    T _data;
    ListNode(const T& x = T()) 
        :_next(nullptr)
        , _last(nullptr)
        , _data(x)
    {  }
}

//迭代器

template<class T, class Ref, class Ptr> //T表示数据类型,Ref表示T& 或 const T&,Ptr表示T* 或 const T*
struct ListIterator
{
    typedef ListNode<T>* PNode;   //结点
    typedef ListIterator<T, Ref, Ptr> Self; //迭代器
    PNode _pNode;  //结点成员
    ListIterator(PNode pNode = nullptr);  //传入结点的构造函数

    ListIterator(const Self& l); //传入迭代器的构造函数
 
    Ref operator*(); //*操作符重载,相当与指针的解引用,直接返回具体数据
    
    Ptr operator->(); //->操作符重载,这里我们实现"->"指向T类型数据

    Self& operator++(); //后置++,要返回迭代器本身
  
    Self operator++(int); //前置++

    Self& operator--(); //后置--

    Self operator--(int); //前置--

    bool operator!=(const Self& l); //"!="操作符重载

    bool operator==(const Self& l); //"=="操作符重载

};


一,容器的结构设计

        list容器在建立初就先要确定“ 哨兵结点 ”,因此,这里需在构造函数中确定哨兵结点,而在设计功能函数时,要思考运用什么类型。这里,我们的结构设计如下:

template<class T>
class list
{
    typedef ListNode<T> Node; 
    typedef Node* PNode;  
public:
    typedef ListIterator<T, T&, T*> iterator; //list迭代器
    typedef ListIterator<T, const T&, const T*> const_iterator;  //const型迭代器,指向const型

    list();  //无参构造

    list(int n, const T& value = T()); //n个T类型数据的构造
    
    template <class Iterator> 
    list(Iterator first, Iterator last); //迭代器方式的构造
    
    list(const list<T>& l); //list的拷贝构造
    
    list<T>& operator=(const list<T> l); //赋值运算符重载
    
    ~list(); //析构函数的使用
   
    iterator begin(); //返回头结点的迭代器
    
    iterator end();  //返回指向尾结点下一个结点的迭代器
 
    const_iterator begin() const; //const_iterator型begin的情况,运用const修饰this指针表示begin函数重载
    
    const_iterator end() const;
    
    size_t size()const; //容器大小
    
    bool empty()const; //判断容器是否为空
    
    T& front(); //返回首元素
    
    const T& front()const; //const_iterator型front的情况,const修饰表示重载
    
    T& back();  //返回尾元素
    
    const T& back()const;  //const_iterator型back()情况
    
    void push_back(const T& val); //尾插
    
    void pop_back(); //尾删
    
    void push_front(const T& val);  //头插
   
    void pop_front(); //头删

    iterator insert(iterator pos, const T& val); //在pos迭代器指向的位置插入数据val,返回此刻位置的迭代器

    iterator erase(iterator pos);// 删除pos位置的节点,返回该节点的下一个位置

    void clear(); //清空所有结点
    
    void swap(list<T>& l); //实现队列的交换

private:
    void CreateHead(); //运用此函数确定" 哨兵结点 "以及哨兵结点内部的结构
    PNode _pHead; //哨兵结点
};


二,构造函数与赋值运算符

构造函数

        构造函数需确定“ 哨兵结点 ”,因为这里使用链式结构存储,需在开始阶段确定哨兵结点,这样方便后面数据的插入与执行。要注意的是这里设计到动态内存的管理,因此需要进行深拷贝。

void CreateHead()    
{
    _pHead = new Node;
    _pHead->_pNext = _pHead;  
    _pHead->_pPre = _pHead;
}

//无参构造,直接确定哨兵结点即可
list()
{
    CreateHead();
}

//实现插入n个数据的构造,这里运用了内部的功能函数

list(int n, const T& value = T())
{
    CreateHead();
    for (int i = 0; i < n; i++)
    {
        push_back(value);  //直接未插即可
    }
}

//迭代器方式构造

template <class Iterator>
list(Iterator first, Iterator last)
{
    CreateHead();
    Iterator it = first;
    while (it != last)
    {
        push_back((it._pNode)->_val);
        it++;
    }
}

//拷贝构造

list(const list<T>& l)
{
    CreateHead();
    *this = l; 
//这里直接运用赋值运算符
}

赋值运算符

        这里唯一要注意的是赋值运算符要实现深拷贝。

list<T>& operator=(const list<T> l)
{
    iterator it = l.begin();
    for (size_t i = 0; i < l.size(); i++)
    {
        push_back((it._pNode)->_val);
        it++;
    }
    return *this;
}


三,析构函数

        析构函数的设计只需诼渐释放所有结点即可,注意,释放结点时要将“ 哨兵结点 ”一并释放,代码如下:

~list()
{
    clear();  //先清空所有数据结点
    delete _pHead; //释放哨兵结点
    _pHead = nullptr;
}


四,list容器接口

1,begin和end

        这里的begin()与end()返回的分别是第一个结点的迭代器与最后一个结点的迭代器,因此,这里分为const迭代器型与非const迭代器型,在设计时为了实现函数重载,这里我们可使用const来修饰this指针进行区分。还有就是注意隐式类型的转换.。

//非const迭代器的使用

iterator begin()
{
    return _pHead->_pNext;  //这里返回的结点,用迭代器接收,迭代器内部有结点类型的构造函数,可以进行隐式类型的转换
}
iterator end()
{
    return _pHead;
}

//const迭代器的使用

const_iterator begin() const  
{
    return _pHead->_pNext;  //这里直接返回即可,相当于不管传入的数据,我们直接返回一个const成员
}
const_iterator end() const   
{
    return _pHead;  
}

2,insert和erase

        insert和erase返回的都是迭代器,由于迭代器内部我们实现了结点的构造函数,因此可以直接返回结点进行隐式类型转换。

// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val)
{
    PNode tem = new Node(val);
    tem->_pNext = pos._pNode;
    tem->_pPre = (pos._pNode)->_pPre;
    (pos._pNode)->_pPre->_pNext = tem;
    (pos._pNode)->_pPre = tem;
    return tem; //因为iterator封装中存在tem类型的构造函数,因此这里可以进行隐式类型转换
}
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos)
{
    assert(_pHead->_pNext != _pHead);
    iterator it = pos;
    PNode next = (pos._pNode)->_pNext;
    delete pos._pNode;
    return next;
}

3,其它常用接口函数

        在list内部,其它常用接口有size()、empty()、front()、back()、push_back()、 pop_back()、push_front()、pop_front()、clear()、swap() 等,接口在实现时较为简单,我们直接实现,如下:

size_t size()const
{
    size_t count = 0;
    iterator tem = begin();
    while (tem != end())
    {
        count++;
        tem++;
    }
    return count;
}
bool empty()const
{
    return _pHead->_pNext == _pHead;
}
T& front()
{
    return _pHead->_pNext->_val;
}
const T& front()const  //const迭代器返回
{
    //注意:这里不能使用return const _pHead->_pNext->_val;因为这里的错误相当于T a = front()即T a = const _pHead->_pNext->_val;
    //const是用来修饰类型的,不是直接修饰数据的

    return _pHead->_pNext->_val;
}
T& back()
{
    return _pHead->_pPre->_val;
}
const T& back()const  //const迭代器返回
{
    return _pHead->_pPre->_val;
}
void push_back(const T& val) 
{
    insert(end(), val);
}
void pop_back()
{
    erase(--end());
}
void push_front(const T& val) 
{
    insert(begin(), val);
}
void pop_front() 
{
    erase(begin()); 
}
void clear()
{
    iterator it(begin());
    while (it != end())
    {
        it = erase(it);
    }
}
void swap(list<T>& l)
{
    std::swap(_pHead, l._pHead);
}

        总:list容器的模拟实现跟部分容器可能有些难度,这里注重要注意类型使用和转换,迭代器的模拟以及构造赋值与析构。功能实现的逻辑基本与链式逻辑一样。文章来源地址https://www.toymoban.com/news/detail-829421.html

到了这里,关于【C++】list链表容器功能模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ stl容器list的底层模拟实现

    目录 前言: 1.创建节点 2.普通迭代器的封装 3.反向迭代器的封装 为什么要对正向迭代器进行封装? 4.const迭代器 5.构造函数 6.拷贝构造 7.赋值重载 8.insert 9.erase 10.析构 11.头插头删,尾插尾删 12.完整代码+简单测试 总结: 1.创建节点 注意给缺省值,这样全缺省就会被当做默认

    2024年04月23日
    浏览(44)
  • 【C++】容器篇(二)——List的基本概述以及模拟实现

    前言: 在上期,我们学习了STL库中的第一个容器--vector ,今天我将给大家介绍的是 库中的另外一个容器--List。其实,有了之前学习 vector 的知识,对于List 的学习成本就很低了。 目录 (一)基本介绍 1、基本概念 2、list 与 forward_list 的比较 3、特点 (二)list的使用 1、list的

    2024年02月06日
    浏览(43)
  • 【C++】反向迭代器的模拟实现通用(可运用于vector,string,list等模拟容器)

    🌏博客主页: 主页 🔖系列专栏: C++ ❤️感谢大家点赞👍收藏⭐评论✍️ 😍期待与大家一起进步! 我们要写出一个通用的反向迭代器模拟而且在保证代码简介不繁琐的的情况下,一定程度上使用我们自己模拟的已经封装好的iterator迭代器可以简化许多步骤,首先我们要知

    2024年02月14日
    浏览(53)
  • 深入篇【C++】手搓模拟实现list类(详细剖析底层实现原理)&&模拟实现正反向迭代器【容器适配器模式】

    1.一个模板参数 在模拟实现list之前,我们要理解list中的迭代器是如何实现的。 在vector中迭代器可以看成一个指针,指向vector中的数据。它的解引用会访问到具体的数据本身,++会移动到下一个数据位置上去,这些都是因为vector具有天生的优势:空间上是连续的数组,这样指

    2024年02月15日
    浏览(44)
  • 【STL】“list“容器从使用到模拟实现

    🎉博客主页:小智_x0___0x_ 🎉欢迎关注:👍点赞🙌收藏✍️留言 🎉系列专栏:C++初阶 🎉代码仓库:小智的代码仓库 list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 list的底层是 双向链表结构 ,双向链表中每个元素存储在

    2024年02月16日
    浏览(70)
  • STL容器 -- list的模拟实现(配详细注释)

    C++ STL(Standard Template Library,标准模板库)提供了一组通用的模板类和函数,用于实现常用的数据结构和算法。其中之一是 std::list,它实现了一个双向链表。 std::list 是一个容器,用于存储一系列的值。与数组和向量等连续存储的容器不同,std::list 使用链表作为底层数据结构

    2024年02月16日
    浏览(48)
  • 【C++模拟实现】list的模拟实现

    作者:爱写代码的刚子 时间:2023.9.3 前言:本篇博客关于list的模拟实现和模拟实现中遇到的问题 list模拟实现的部分代码 list模拟实现中的要点 const_iterator的实现 我们选择使用模版参数,复用iterator的类,设置三个模版参数: templateclass T,class Ref,class Ptr 并且 typedef __list_iter

    2024年02月09日
    浏览(52)
  • 【STL源码分析】c++,List双向链表源码分析。自己实现list双向链表。

    参考链接:https://blog.csdn.net/man_sion/article/details/71003095? 先抽取要实现的功能,由于迭代器有些麻烦,就不使用了。要实现的功能有,push_back,pop_back,insert(指定位置,指定值),insert(指定位置,list,区间值),reverse,clear,getsize,begin,end,构造和析构函数,empty。 相关力扣题目:设计

    2024年02月03日
    浏览(44)
  • C++ list 模拟实现

      目录 1. 基本结构的实现 2.  list() 3. void push_back(const T val) 4. 非 const 迭代器 4.1 基本结构  4.2 构造函数  4.3 T operator*() 4.4  __list_iterator operator++() 4.5 bool operator!=(const __list_iterator it) 4.6 T* operator-() 5. const 迭代器  6. begin()  end() ​编辑 7. iterator insert(iterator pos, const T v

    2024年02月08日
    浏览(47)
  • C++ list模拟实现

    源码中的list实现为 带头双向链表   list类的对象有两个成员:指向头结点的指针_head,统计数据个数的_size 在模拟实现list之前,需要先模拟实现 结点类,迭代器类 结点类:三个成员,_data _prev _next , 实现成struct (也是类,不过与class不同的是,它的成员都是公开的,都可以

    2024年02月11日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包