一、vector和list的对比
vector
是一个可以动态增容的数组。
list
是一个带头双向循环链表。
功能 | vector | list |
---|---|---|
底层实现 | 动态增容数组 | 带头双向循环链表 |
随机访问元素 | 支持随机访问任意位置的元素,O(1)访问 | 不支持随机访问任意位置的元素,O(N)访问 |
插入和删除元素 | 头尾部元素的操作是O(1),中间位置元素的操作是O(N) | 任意位置的元素操作都是O(1) |
增容 | 空间不足时会动态的增容,增容时首先开辟新空间,拷贝元素,释放旧空间。代价很大 | 没有增容。 |
空间利用率 | 底层为连续空间,不容易导致空间碎片化,空间利用率高,缓存利用率高,运行时缓存命中率高。 | 底层的节点是动态开辟的,容易造成内存的碎片化,空间利用率不高,缓存利用率也不高。 |
迭代器实现 | 原生指针 | 需要对原生指针包装进行迭代器运算符的重载 |
迭代器失效 | 插入元素,有可能会扩容导致所有的迭代器都会失效。删除元素时,当前位置的迭代器和后面的迭代器都会失效。 | 插入元素时,迭代器不会失效。删除元素时,只有当前迭代器会失效。 |
使用场景 | 高效存储,支持随机元素访问,不关系大量元素的插入效率 | 大量的元素插入和删除,不关系元素的访问效率 |
总结:vector
和list
两个容器是互补的容器,使用起来相辅相成。
二、list的模拟实现
#include <iostream>
using namespace std;
namespace myList
{
// 双链表中的节点定义
template<class T>
struct _list_node
{
T _val;
_list_node<T>* _prev;
_list_node<T>* _next;
_list_node(const T& val = T()):
_val(val),
_prev(nullptr),
_next(nullptr)
{}
};
// 迭代器需要包装一下
template<class T, class Ref, class Ptr>
struct _list_iterator
{
typedef _list_node<T> node;
typedef _list_iterator<T, Ref, Ptr> Sef;
node* _pnode;
_list_iterator(node* pnode):
_pnode(pnode)
{}
Ref operator* ()
{
return _pnode->_val;
}
Ptr operator-> ()
{
return &_pnode->_val;// 这里编译器优化掉了一个->,否则应该是->->
}
Sef& operator++() // 前置++
{
_pnode = _pnode->next;
return *this;
}
Sef operator++(int) // 后置++
{
Sef tmp(*this);// 这里需要使用的就是浅拷贝
_pnode = _pnode->_next;
return tmp;
}
Sef& operator--() // 前置--
{
_pnode = _pnode->_prev;
return *this;
}
Sef operator--(int) // 后置--
{
Sef tmp(*this);
_pnode = _pnode->_prev;
return tmp;
}
bool operator!= (const Sef& it) const
{
return _pnode != it._pnode;
}
bool operator== (const Sef& it) const
{
return _pnode == it._pnode;
}
};
template<class T>
struct list
{
typedef _list_node<T> node;
public:
// 迭代器及其函数
typedef _list_iterator<T, T&, T*> iterator;
typedef _list_iterator<T, const T&, const T*> const_iterator;
// _head只是一个指针返回迭代器对象的时候需要强制类型转换
iterator begin()
{
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
const_iterator begin() const
{
return const_iterator(_head->_next);
}
const_iterator end() const
{
return const_iterator(_head);
}
// 默认构造函数
list():
_head(new node)
{
_head->_next = _head;
_head->_prev = _head;
}
// 拷贝构造函数
list(const list<T>& lt):
_head(new node)
{
_head->_next = _head;
_head->_prev = _head;
const_iterator it = lt.begin();
while (it != lt.end())
{
push_back(*it);
it ++;
}
}
// 赋值运算符重载
list<T>& operator= (list<T> lt)
{
swap(_head, lt._head);
return *this;
}
// 赋值运算符的传统写法
//list<T>& operator= (const list<T>& lt)
//{
// if (this != <)
// {
// clear();
// list<int>::const_iterator it = lt.begin();
// while (it != lt.end())
// {
// push_back(*it);
// it ++;
// }
// return *this;
// }
//}
// 先将链表中的数据清空,然后将头结点空间释放掉
~list()
{
clear();
delete _head;
}
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
void push_front(const T& val)
{
insert(begin(), val);
}
void push_back(const T& val)
{
// 复用接口
insert(end(), val);
//node* newNode = new node(val);
//node* tailNode = _head->_prev;
//
//tailNode->_next = newNode;
//newNode->_prev = tailNode;
//newNode->_next = _head;
//_head->_prev = newNode;
}
// 在pos位置之前插入val
void insert(iterator pos, const T& val)
{
node* newNode = new node(val);
node* cur = pos._pnode;
node* prev = cur->_prev;
prev->_next = newNode;
newNode->_prev = prev;
newNode->_next = cur;
cur->_prev = newNode;
}
void pop_front()
{
erase(begin());
}
void pop_back()
{
erase(--end());
}
iterator erase(iterator pos)
{
node* cur = pos._pnode;
node* prev = cur->_prev;
node* next = cur->_next;
delete cur;
cur = nullptr;
prev->_next = next;
next->_prev = prev;
return iterator(next);
}
bool empty() const
{
return _head->_next == _head;
}
private:
node* _head;
};
}