c++学习笔记-----list

一、list的介绍及使用

(一)什么是list

1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
2.list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)。

在这里插入图片描述

(二)list的使用
1.list的构造
在这里插入图片描述

 // List的构造
    list()
	{
		CreateHead();
	}

	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();
		while (first != last)
		{
			push_back(*first);
			++first;
		}
	}

	list(const list<T>& l)
	{
		CreateHead();
		list<T> temp(l.begin(), l.end());
		swap(temp);
	}

	list<T>& operator=(const list<T> l)
	{
		swap(l);
		return *this;
	}
	void CreateHead()
	{
		_phead = new Node;
		_phead->_prev = _phead;
		_phead->_next = _phead;
	}

2.list容量及判空
在这里插入图片描述

// List Capacity
	size_t size()const
	{
		size_t sz = 0;
		Node* cur = _phead->_next;
		while (cur != _phead)
		{
			sz++;
			cur = cur->_next;
		}
		return sz;
	}
	bool empty()const
	{
		return size() == 0;
	}

3.list返回第一个和最后一个节点值。

在这里插入图片描述

	T& front()
	{
		assert(_phead != empty());
		return _phead->_next->_val;
	}
	T& back()
	{
		assert(_phead != empty());
		return _phead->_prev->_val;
	}

4.list增删交换和清空
在这里插入图片描述

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());
	}

    // 在pos位置前插入值为val的节点

	iterator insert(iterator pos, const T& val)
	{
		pNode newnode = new Node(val);
		pNode posnode = pos._pNode;
		newnode->_prev= posnode->prev;
		posnode->_prev->_next = newnode
		newnode->_next = posnode;
		posnode->prev = newnode;
		return iterator(newnode);
	}

    // 删除pos位置的节点,返回该节点的下一个位置

	iterator erase(iterator pos)
	{
		PNode dnode = pos._pNode;
		PNode nnode = dnode->_next;
		dnode->_prev->_next = dnode->_next;
		dnode->_next->_prev = dnode->_prev;
		delete dnode;
		return iterator(nnode);
	}

	void clear()
	{
		iterator it = begin();
		while(it!=end())
		{
			it=erase(it);
		}
	}

	void swap(list<T>& l)
	{
		PNode temp = l._phead;
		l = _phead;
		_phead = temp;
	}

5.迭代器的使用

iterator begin()
	{
		return _phead->_next;
	}

	iterator end()
	{
		return _phead;
	}

二、list下迭代器类的定义及使用

(一)iterator类的定义
因为list中内存不是连续的,我们使用迭代器时不能像在vector下使用对迭代器++从而来进行访问,这时我们就需要对迭代器进行运算符重载,从而使它达到访问list下的不连续内存,这里我们要将迭代器定义为struct而不是class,因为class具有封装性,实际应用中,我们需要随时访问该类,这个类不需要析构函数,因为本身就是一个结构体指针,没有必要。

  struct ListIterator
  {
    typedef ListNode<T>* PNode;
    typedef ListIterator<T, Ref, Ptr> Self;
    PNode _pNode;
	ListIterator(PNode pNode = nullptr)
	  :_pNode(pNode)
	  {}
	T& operator*()
	{
		return PNode->_val;
	}
	T* operator->()
	{
		return &PNode->_val;
	}
	Self& operator++()
	{
		_pNode = _pNode->_next;
		return *this;
	}
	Self operator++(int)
	{
		self temp(*this);
		_pNode = _pNode->_next;
		return temp;
	}
	Self& operator--()
	{
		_pNode = _pNode->_prev;
		return *this;
	}
	Self& operator--(int)
	{
		self temp(*this);
		_pNode = _pNode->_prev;
		return temp;
	}
	bool operator!=(const Self& l)
	{
		return _pNode != l._pNode;
	}
	bool operator==(const Self& l)
	{
		return !(*this != l);
	}
  };

(二)list的迭代器失效

在list中,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

三、list与vector的对比

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ishao97

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值