【C++】list的模拟实现

文章目录

    • 1.list 底层
    • 2. list的模拟实现
      • 1. list_node 类设计
      • 2. list类如何调用类型
      • 3 .push_back(正常实现)
      • 4. 迭代器的实现
        • 第一个模板参数T
        • const迭代器
        • 第二个模板参数Ref
        • 第三个模板参数Ptr
        • 对list封装的理解
      • 5. insert
      • 6.push_back与 push_front(复用)
      • 7. erase
      • 8. pop_back与pop_front (复用)
      • 9. clear 清空数据
      • 10. 迭代器区间构造
      • 12. 拷贝构造
        • 传统写法
        • 现代写法
      • 13. 赋值
    • 3.完整代码

1.list 底层

list为任意位置插入删除的容器,底层为带头双向循环链表

begin() 代表第一个结点,end()代表最后一个结点的下一个

2. list的模拟实现

1. list_node 类设计

template<class T>
	struct list_node
	{
		list_node<T>* _next;
		list_node<T>* _prev;
		T _data;

	};

C++中,Listnode作为类名,而next和prev都是类指针,指针引用成员时使用->,而对象引用成员时使用 .
通过显示实例化,将两个类指针指定类型为T

2. list类如何调用类型

Listnode 代表类型
Listnode 代表类名 + 模板参数 才是类型
而_head 以及创建新节点前都需加上类型

3 .push_back(正常实现)

void push_back(const T&x)//尾插
        {
            node* newnode = new node(x);
            node* tail = _head->_prev;
            tail->_next = newnode;
            newnode->_prev = tail;
            newnode->_next = _head;
            _head->_prev = newnode;
        }

当我们想要创建一个节点时,需要调用node的构造函数
typedef list_node node ,node是由 list_node 类提供的

list_node(const T& x=T())//list类的构造函数
			:_next(nullptr)
			, _prev(nullptr)
			, _data(x)
		{
		}

最好在构造函数处提供全缺省,对于内置类型int可以使用0,但对于自定义类型来说就不可以,所以为了满足泛型的要求,使用匿名对象调用默认构造函数

4. 迭代器的实现

若在数组上有一个int类型的指针,解引用是int类型的数据,再++可以加载下一个位置,因为物理空间是连续的

同样若在链表上,解引用类型为 node,再++不能到下一个节点,因为物理空间不连续
所以构造迭代器通过封装节点的指针来进行构造 (后面会讲)

第一个模板参数T

创建一个_list_iterator的类,来实现迭代器功能

template<class T>
    struct _list_iterator
    {
        typedef list_node<T> node;
        typedef _list_iterator<T> self;
        node* _node;
        
        _list_iterator(node* n)
            :_node(n)
        {

        }
        T& operator*()//解引用 
        {
            return _node->_data;
        }
        _list_iterator<T>& operator++()//返回迭代器
        {
            _node = _node->_next;//指向下一个节点
            return *this;
        }
        bool operator!=(const self&s)
        {
            return _node != s._node;
        }
    };

在list类中,调用迭代器实现begin()和end()功能
typedef _list_iterator<T,T&,T*> iterator,
通过typedef 将_list_node类模板定义为iterator

iterator begin()
		{
			return iterator(_head->_next);//通过匿名对象访问第一个数据
		}
		iterator end()
		{
			return iterator(_head);//通过匿名对象访问最后一个数据的下一个
		}

在list类中实现begin()和end(),内部调用_list_node类的构造函数

const迭代器

假设第一个代表的是T * ,而第二个代表的 T * const,保护迭代器本身不可以被修改,而我们想要保护迭代器指向的内容不可被修改即 const T*

复制_list_iterator类中的内容,并将名字修改为const_list_iterator
只需修改*operator类型为cosnt T& ,说明解引用后的数据返回不能被修改

template<class T>
    struct _list_const_iterator
    {
        typedef list_node<T> node;
        typedef _list_const_iterator<T> self;
        node* _node;

        _list_const_iterator(node* n)
            :_node(n)
        {

        }
        const T& operator*()//解引用 
        {
            return _node->_data;
        }
        self& operator++()//前置++
        {
            _node = _node->_next;//指向下一个节点
            return *this;
        }
        self& operator++(int)//后置++
        {
            self ret = *this;
            _node = _node->_next;
            return ret;
        }
        self& operator--()//前置--
        {
            _node = _node->_prev;
            return *this;
        }
        self& operator--(int)//后置--
        {
            self ret = *this;
            _node = _node->_prev;
            return ret;
        }
        bool operator!=(const self& s)//!=
        {
            return _node != s._node;
        }
        bool operator==(const self& s)//==
        {
            return _node == s._node;
        }
    };

第二个模板参数Ref

迭代器和const迭代器只有 *operator 的返回值不同,
只需在模板中添加一个参数即可使用一个迭代器实现迭代器和const 迭代器的功能

第三个模板参数Ptr

对于内置类型int使用解引用找到对应数据,而自定义类型需使用->寻找下一个节点

版权声明:本文为博主作者:风起、风落原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/qq_62939852/article/details/129440139

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2024年1月3日
下一篇 2024年1月3日

相关推荐