面试热点题:stl中vector与list的优缺点对比、以及list的迭代器与vector迭代器的区别

vector的优点

  1. 下标随机访问
    vector的底层是一段连续的物理空间,所以支持随机访问
  2. 尾插尾删效率高
    跟数组类似,我们能够很轻易的找到最后一个元素,并完成各种操作
  3. cpu高速缓存命中率高
    因为系统在底层拿空间的时候,是拿一段进cpu,不是只拿单独一个,会提前往后多拿一点,vector的物理地址是连续的,所以我们再拿到数据的时候,cpu访问后面的数据会更快

vector的缺点

  1. 前面部分的插入删除数据效率低
    如果我们要在前面或中间插入或者删除数据,我们不能直接删,我们需要挪动数据,去覆盖或者增加一段空间,这样我们挪动数据的效率就是O(N)
  2. 扩容有消耗,可能存在一定的空间浪费
    正常情况下我们vector的扩容机制是一旦达到当前空间的capacity(容量)那么我们扩容原空间的1.5倍或者2倍数(vs一般是1.5倍而g++是2倍),这样扩容就有可能导致空间浪费,而且频繁扩容也会影响效率

list的优点

  1. 按需申请释放,不需要扩容
    list是一个带头双向循环链表,那么链表就是一个个独立的空间链接起的,需要多少,就new多少,不存在空间浪费
  2. 任意位置的插入删除效率高(对比vector)
    因为list是双向循环链表,我们需要插入新的元素只需要改变原数据的next与prev(下一个和上一个),所以我们的插入删除效率是O(1)

list的缺点

  1. 不支持下标随机访问
    因为我们list是链表,我们存放数据的物理地址并不是连续的,所以我们也就不能支持随机访问
  2. cpu高速缓存命中率低
    还是跟它的物理空间地址不连续有关,cpu提前存的一段数据,可能跟下一个数据完全没有联系,因为它们空间不连续,所以也就命中率低

vector与list就是一个互补的关系

迭代器的差别

既然list是不支持随机访问,那么我们该怎么去访问数据呢?我们肯定不能直接去访问底层的next与prev,我们还是使用迭代器,那么这个迭代器与vector和string的迭代器有何差别呢?

迭代器有什么价值?

  1. 封装底层实现,不暴露底层的实现细节
  2. 提供统一的访问方式,降低使用成本

iterator:

  1. 内嵌类型(int double)
  2. 行为像指针一样的封装后的类型

在这里插入图片描述
在这里插入图片描述
参考list迭代器模拟底层代码:

template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
    
    
		typedef list_node<T> node;
		typedef __list_iterator<T, Ref, Ptr> Self;
		node* _pnode;

		__list_iterator(node* p)
			:_pnode(p)
		{
    
    }
		
		Ptr operator->()
		{
    
    
			return &_pnode->_data;
		}
		
		Ref operator*()
		{
    
    
			return _pnode->_data;
		}

		Self& operator++()
		{
    
    
			_pnode = _pnode->_next;
			return *this;
		}

		Self operator++(int)
		{
    
    
			Self tmp(*this);
			_pnode = _pnode->_next;		
			return tmp;
		}

		Self& operator--()
		{
    
    
			_pnode = _pnode->_prev;
			return *this;
		}

		Self operator--(int)
		{
    
    
			Self tmp(*this);
			_pnode = _pnode->_prev;
			return tmp;
		}

		bool operator!=(const Self& it) const
		{
    
    
			return _pnode != it._pnode;
		}

		bool operator==(const Self& it) const
		{
    
    
			return _pnode == it._pnode;
		}
	};

template<class T, class Ref, class Ptr>这里使用三个模板参数是为了区分普通迭代器与const迭代器

同一个类模板实例化出的两个类型
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;

为什么const迭代器要这样子实例两个类型,不是在普通迭代器前面加上const?
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/DEXTERFUTIAN/article/details/128939232