先前我们讲过vector是连续线性存储的,其访问元素的时间复杂度是,但是插入或者删除元素的时间复杂度是,所以其插入或者删除的效率比价低。有什么容器的插入或者删除的效率是常数时间呢? 有啊~~ 就是list。list的每次插入或者删除元素时,配置或者释放一个内存空间,其时间复杂度永远是。现在就让我们来了解一下list的底层实现吧。
首先让我们来看一下list的节点。
template<typename T>
struct Listnode {
T value;
Listnode<T>* prev;
Listnode<T>* next;
public:
Listnode() :value(0) {};
Listnode(const T& _value) :value(_value) {};
};
所以list是一个双向链表。
- 我们都知道vector是连续线性存储的,因此其迭代器就是原生指针。通过list的节点我们知道:list是一个双向链表结构。这就告诉我们其迭代器不是原生指针,而是class type。因此我们必须对其迭代器进行封装。
list的迭代器:
template<typename T>
struct Listiteratortype {
typedef T Value_type;
typedef T* Pointer;
typedef T& Reference;
typedef size_t Size_type;
typedef size_t Difference_type;
};
template<typename T>
class Listiterator {
public:
Listiterator(Listnode<T>& _node) :node(_node) {};
Listiterator():node(nullptr) {};
Listiterator(const Listiterator<T>& _listiterator) :node(_listiterator.node) {};
~Listiterator() { if (node!=nullptr) delete node; };
public:
typename Listiteratortype<T>::Reference operator*()const;
typename Listiteratortype<T>::Pointer operator->()const;
typename Listiterator<T>& operator++();
typename Listiterator<T>& operator--();
typename Listiterator<T>* operator++(int);
typename Listiterator<T>* operator--(int);
bool operator==(const Listiterator<T>& _listiterator);
bool operator!=(const Listiterator<T>& _listiterator);
private:
Listnode<T>* node;
};
list迭代器的实现
template<typename T>
bool Listiterator<T>::operator==(const Listiterator<T>& _listiterator) {
if (_listiterator.node == node)
return true;
else
return false;
}
template<typename T>
bool Listiterator<T>::operator!=(const Listiterator<T>& _listiterator) {
if (_listiterator.node != node)
return true;
else
return false;
}
template<typename T>
typename Listiteratortype<T>::Reference Listiterator<T>::operator*()const {
return node->value;
}
template<typename T>
typename Listiteratortype<T>::Pointer Listiterator<T>::operator->()const {
return &(node->value);
}
template<typename T>
typename Listiterator<T>& Listiterator<T>::operator++() {
node = node->next;
return *this;
}
template<typename T>
typename Listiterator<T>& Listiterator<T>::operator--() {
node = node->prev;
return *this;
}
template<typename T>
typename Listiterator<T>* Listiterator<T>::operator++(int) {
auto temp = *this;
node = node->next;
return *this;
}
template<typename T>
typename Listiterator<T>* Listiterator<T>::operator--(int) {
auto temp = *this;
node = node->prev;
return *this;
}
链表的存储不是连续线性存储的,那么list的存储也不是。因此我们便可以知道:list的插入和删除操作并不会导致迭代器的失效(也可以理解为局部的改变,不会引起整体的变化)。我们已经知道list的底层是双向链表,但是更重要的是:list的底层实现是双向环状链表结构。为什么是环状的链表结构? 我的理解是因为链表的插入和删除的时间复杂度是常数,但是对对数据的访问的时间复杂度是线性时间,环状结构更利于对数据的访问吧。
list的头文件
template<typename T>
class List {
public:
List() :node(new Listnode<T>()) {
node->next = node;
}
List(const size_t n, const T* t);
~List();
public:
Listiterator<T> begin()const;
Listiterator<T> end()const;
bool empty()const;
typename Listiteratortype<T>::Size_type size()const;
typename Listiteratortype<T>::Reference front()const;
typename Listiteratortype<T>::Reference back()const;
void push_back(const T& key);
Listiterator<T> insert(Listiterator<T>& position, const T& value);
Listiterator<T> erase(Listiterator<T>& position);
void push_back(const T& value);
void pop_back();
void push_front(const T& value);
void pop_front();
void clear();
private:
Listnode<T>* node;
void destory()noexcept;
Listnode<T>* construct(const size_t n, const T* t)noexcept;
};
list的实现
template<typename T>
void List<T>::destory()noexcept {
auto first = node->next;
auto last = node;
while (first != last) {
delete first;
first = nullptr;
first=first->next;
}
delete last;
last = nullptr;
}
template<typename T>
Listnode<T>* List<T>::construct(const size_t n, const T* t)noexcept {
Listnode<T>* p = node;
for (int i = 0; i < n; ++i) {
Listnode<T>* newnode = new Listnode<T>();
newnode->value = t[i];
p->next = newnode;
newnode->prev = p;
}
p->next = node;
node->prev = p;
}
template<typename T>
List<T>::List(const size_t n, const T* t) {
construct(n, t);
}
template<typename T>
List<T>::~List() {
destory();
}
template<typename T>
Listiterator<T> List<T>::begin()const {
node = node->next;
return Listiterator<T>listiterator(node);
}
template<typename T>
Listiterator<T> List<T>::end()const {
return Listiterator<T>listiterator(node);
}
template<typename T>
bool List<T>::empty()const {
if (node->next == node)
return true;
else
return false;
}
template<typename T>
typename Listiteratortype<T>::Size_type List<T>::size()const {
size_t count = 0;
auto first = node->next;
auto last = node;
while (first != last) {
++count;
first=first->next;
}
return count;
}
template<typename T>
typename Listiteratortype<T>::Reference List<T>::front()const {
node = node->next;
return node->value;
}
template<typename T>
typename Listiteratortype<T>::Reference List<T>::back()const {
node = node->prev;
return node->value;
}
template<typename T>
Listiterator<T> List<T>::insert(Listiterator<T>& position, const T& value) {
Listnode<T>* newnode = new Listnode<T>(value);
newnode->next = position.node;
newnode->prev = position.node->prev;
position.node->prev->next = newnode;
position.node->prev = newnode;
return Listiterator<T>(newnode);
}
template<typename T>
Listiterator<T> List<T>::erase(Listiterator<T>& position) {
Listnode<T>* position_next = position.node->next;
Listnode<T>* position_prev = position.node->prev;
position_next->prev = position_prev;
position_prev->next = position_next;
delete position;
return Listiterator<T>(position_next);
}
template<typename T>
void List<T>::pop_back() {
Listiterator<T>* tmp = end();
--tmp;
erase(tmp);
}
template<typename T>
void List<T>::pop_front() {
erase(begin());
}
template<typename T>
void List<T>::push_back(const T& value) {
insert(end(), value);
}
template<typename T>
void List<T>::push_front(const T& value) {
insert(begin(), value);
}
template<typename T>
void List<T>::clear() {
Listnode<T>* first = node->next;
Listnode<T>* last = node;
while (first != last) {
delete first;
first = first->next;
}
node->next = node;
node->prev = node;
}
以上代码是我写的简单的list。 如果有不理解的或者错误的地方,欢迎指出哦~~~