C++——list常见函数的使用和模拟实现(1)

        容器list的本质就是我们之前模拟实现过的链表中的双向带头循环链表,因此在使用的时候和之前我们实现的链表的功能是类似的。但是作为容器,list相较于我们之前实现的链表增加了迭代器的使用,同时这里的迭代器和之前模拟实现string和vector的迭代器也有所不同。因为string和vector的迭代器都可以用原生的指针来模拟实现,但是list中的每一个结点都是分散的,同时每个结点还要保存上一个结点以及下一个结点的信息,所以用原生的指针来实现不是理想,具体的实现方式会在后面具体提到。

        一、构造函数

        list作为容器也有多种构造函数,这里我们只对构造一个空的list进行模拟实现,其中只进行使用介绍。

        链表中的结点不仅需要存储数据,同时还要记录前后结点的信息,因此我们需要用一个结构体来作为链表的结点。因为我们的list能够存储各种类型的数据,所以这里存储的数据类型要用模版来代替。

	template<class T>
	struct list_Node
	{
		T _data;
		list_Node* _next;
		list_Node* _prev;
        //T的类型是自定义类型时,T()会调用T类型的构造函数
        //当T是内置类型是,T()会将T初始化为默认值
		list_Node(const T& data = T())
			:_data(data)
			,_next(nullptr)
			,_prev(nullptr)
		{
		}
	};

        由于list的本质上是一个双向带头的循环链表是,所以我们只需要记录list的头结点和就能找到这一整个链表了,同时我们还需要记录一下list内部数据的个数方便后续的操作。因为list能够存储的数据类型是不确定的,我们的结点是一个模版类,所以我们的list也要是一个模版类。它的基本结构如下:

template<class T>
class list
{
    //在后面的操作中我们会经常用到结点的类型,因此我们直接把它typedef成Node方便操作
    typedef list_Node<T> Node;

    Node* _head;
    size_t _size;
}

        因为list的本质是一个双向带头的循环链表,所以当构造出一个链表时,它应该要一个用来标记的头结点,不论链表中的是否有数据,或者有多少个数据,我们链表都要满足它的基本结构的特点,所以这个用来标记的头结点也把它指向前后结点的指针都指向自己,这样才满足了条件。

list()
{
    _head = new Node;
    _head->_next = _head;
    _head->_prev = _head;
    _size = 0;			
}
//构造一个包含n个值为val的list
list (size_type n, const value_type& val =value_type())
//用任意迭代器把[first,last)的数据存入一个list中
list (InputIterator first, InputIterator last)
//list的拷贝构造函数,可以用一个list来构造另外一个list
list (const list& x)

        二、list常见的插入和删除

        和我们实现的list类似,容器list也分别有三种插入和删除的方式,push_back在链表的尾部插入一个数据,push_front在链表的头部插入一个数据,insert在指定位置前插入一个数据;pop_back删除链表尾部的数据,pop_front删除链表头部的数据,erase删除链表指定位置的数据。

        这里先模拟实现在 头部和尾部操作数据的函数,在特定位置操作的函数放在实现了迭代器以后再进行模拟实现。

    void push_back(const T& x)
    {
        //循环链表的首尾相连 头结点的前一个结点就是链表的最后一个数据
        //先保存下插入前尾部数据的信息 方便后续操作
        Node* cur = _head->_prev; 
        Node* newnode = new Node(x);
        //把数据先接到头结点之前的位置 也就是最后一个数据的位置
        _head->_prev = newnode;
        newnode->_next = _head;
        //再把插入前的最后一个数据和新的尾部数据连接起来
        cur->_next= newnode;
        newnode->_prev = cur; 
        ++_size;
    }
    void push_front(const T& x)
    {
        //保存插入前的头部数据
        Node* cur = _head->next;
        Node* newnode = new Node(x);
        //先把新的数据挂在头结点的后面
        _head->_next = newnode;
        newnode->_prev = _head;
        //再把原先的头部数据接到新的头部数据的后面
        cur->_prev = newnode;
        newnode->_next = cur;
        ++_size;
    }
    pop_back()
    {
        //保存尾部数据的信息
        Node* cur = _head->_prev;
        //将尾部数据前一个结点中指向下一个结点的指针指向头结点
        //再把头结点指向前一个结点的指针指向尾部数据的前一个结点
        //改变这两个指针的指向就可以删除尾部的数据
        _head->prev = cur->prev;
        cue->prev->next = _head;
        //再释放掉被删除结点申请的空间
        delete cur;
        --_size;
    }
    pop_front()
    {
        //保存原先的头部数据的信息
        Node* cur =_head->_next;
        //把头结点指向下一个结点的指针指向头部数据的下一个节点
        //再把头部数据下一个结点指向前一个结点的指针指向头结点
        //这样原先的头部数据就被踢出链表了
        _head->_next =cur->_next;
        cur->next->prev =_head;
        //释放被删除结点申请的空间
        delete cur;
        --_size;
    }

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用和提供了关于实现vector的两种方法。其中,引用展示了一个使用reserve和push_back方法的示例,而引用展示了一个使用new和memcpy函数的示例。这两种方法都是常见实现vector的方式。 在第一种方法中,通过reserve函数可以预留足够的内存空间,然后使用push_back函数逐个将元素添加到vector中。这种方法的好处是可以避免不必要的内存重分配,提高了效率。 而第二种方法使用new操作符在堆上分配内存空间,并使用memcpy函数将已有的vector对象的数据复制到新的内存空间中。通过这种方式,可以实现深拷贝,即两个vector对象拥有独立的内存空间。这种方法的好处是可以在不修改原始vector对象的情况下创建一个新的vector对象。 除了以上两种方法,还可以使用其他方式实现vector类。例如,可以使用动态数组来实现vector的底层数据结构,然后通过成员函数实现vector的各种操作,如增加、删除、查找等。 总结来说,c语言模拟实现vector的关键是动态内存管理和对元素的增删改查操作。可以使用预留空间和逐个添加元素的方式,也可以使用动态数组和复制数据的方式来实现vector类。具体的实现方式可以根据需求和实际情况选择。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++——vector模拟实现](https://blog.csdn.net/weixin_49449676/article/details/126813526)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值