一、初始结构的搭建
STL中的list本质上是带头双向循环链表,我在C语言篇数据结构(8)中讲解过,所以这里list结构的模拟实现就直接用C++的形式封装一下就行。
#pragma once
namespace bit
{
template<class T>
struct list_node
{
T _data;
list_node<T>* _prev;
list_node<T>* _next;
list_node(const T& x = T())
:_data(x)
,_prev(nullptr)
,_next(nullptr)
{ }
};
template<class T>
class list
{
typedef list_node<T> Node;
public:
list()
{
_head = new Node;
_head->_prev = _head;
_head->_next = _head;
}
private:
Node* _head;
};
}
结构图如下:

二、成员函数的实现
2.1 尾插
void push_back(const T& x)
{
Node* newnode = new Node(x);
Node* tail = _head->_prev;
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;
}
2.2 普通迭代器
在之前的string和vector的模拟实现中,迭代器都是采用原生指针来实现的。但是在list中,如果仍然用原生指针Node*来实现迭代器的话,解引用得到的并不是我们想要的数据,而是结点。并且,由于物理地址不是连续的,++迭代器也到不了下一个结点。但是可以通过_next指针来访问下一个结点,所以我们可以用类来封装结点的指针,重载运算符,控制迭代器的行为。
template<class T>
struct __list_iterator
{
typedef list_node<T> Node;
Node* _node;
__list_iterator(Node* node)
:_node(node)
{ }
T& operator*()
{
return _node->_data;
}
__list_iterator<T>& operator++()
{
_node = _node->_next;
return *this;
}
__list_iterator<T> operator++(int)
{
__list_iterator<T> tmp(*this);
_node = _node->_next;
return tmp;
}
__list_iterator<T>& operator--()
{
_node = _node->_prev;
return *this;
}
__list_iterator<T> operator--(int)
{
__list_iterator<T> tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const __list_iterator<T>& it) const
{
return _node != it._node;
}
bool operator==(const __list_iterator<T>& it) const
{
return _node == it._node;
}
};
2.3 const迭代器
所谓const迭代器,就是迭代器指向的内容不能修改,但是迭代器本身可以修改。也就是说解引用之后的值不能修改,所以解引用重载函数的返回值应该是const类型的引用。因此我们要重新实现一个类来封装。
template<class T>
struct __list_const_iterator
{
typedef list_node<T> Node;
Node* _node;
__list_const_iterator(Node* node)
:_node(node)
{ }
const T& operator*()
{
return _node->_data;
}
__list_const_iterator<T>& operator++()
{
_node = _node->_next;
return *this;
}
__list_const_iterator<T> operator++(int)
{
__list_const_iterator tmp(*this);
_node = _node->_next;
return tmp;
}
__list_const_iterator<T>& operator--()
{
_node = _node->_prev;
return *this;
}
__list_const_iterator<T> operator--(int)
{
__list_const_iterator<T> tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const __list_const_iterator<T>& it) const
{
return _node != it._node;
}
bool operator==(const __list_const_iterator<T>& it) const
{
return _node == it._node;
}
};
注意:千万不能用typedef const __list_iterator<T> const_iterator来实现,因为const修饰迭代器本身,迭代器无法++。那为什么不重载一个operator*函数呢?道理和上面一样,普通迭代器调用普通的重载函数,被const修饰的迭代器才回去调用重载的函数,迭代器仍然无法++。

但是这两种迭代器终究只是operator*不一样,其他的成员函数都大致一样,实现两个类显得代码有点太冗余了,能不能优化一下呢?当然可以,只需要再增加一个模版参数Ref即可。但是加了一个模版参数之后,代码有很多地方要修改,就会很麻烦,也不方便后续的维护,所以这里把这个模版类型重命名为Self。
template<class T, class Ref>
struct __list_iterator
{
typedef list_node<T> Node;
typedef __list_iterator<T, Ref> Self;
Node* _node;
__list_iterator(Node* node)
:_node(node)
{ }
Ref operator*()
{
return _node->_data;
}
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_node = _node->_next;
return tmp;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const Self& it) const
{
return _node != it._node;
}
bool operator==(const Self& it) const
{
return _node == it._node;
}
};
这样就可以只写一个类了,并且它们是由同一个类模版实例化的两个类型。

2.4 任意位置插入和删除
void insert(iterator pos, const T& val)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* newnode = new Node(val);
newnode->_next = cur;
newnode->_prev = prev;
prev->_next = newnode;
cur->_prev = newnode;
}

在list中,insert并不会导致迭代器失效,但是erase会导致,因此实现erase时要给返回值。
iterator erase(iterator pos)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = next;
next->_prev = prev;
delete cur;
//return iterator(next);
return next;
}

三、完整参考代码
list.h
#pragma once
#include <iostream>
using namespace std;
namespace bit
{
template<class T>
struct list_node
{
T _data;
list_node<T>* _prev;
list_node<T>* _next;
list_node(const T& x = T())
:_data(x)
,_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> Self;
Node* _node;
__list_iterator(Node* node)
:_node(node)
{ }
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_node = _node->_next;
return tmp;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const Self& it) const
{
return _node != it._node;
}
bool operator==(const Self& it) const
{
return _node == it._node;
}
};
/*template<class T>
struct __list_const_iterator
{
typedef list_node<T> Node;
Node* _node;
__list_const_iterator(Node* node)
:_node(node)
{ }
const T& operator*()
{
return _node->_data;
}
__list_const_iterator<T>& operator++()
{
_node = _node->_next;
return *this;
}
__list_const_iterator<T> operator++(int)
{
__list_const_iterator tmp(*this);
_node = _node->_next;
return tmp;
}
__list_const_iterator<T>& operator--()
{
_node = _node->_prev;
return *this;
}
__list_const_iterator<T> operator--(int)
{
__list_const_iterator<T> tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const __list_const_iterator<T>& it) const
{
return _node != it._node;
}
bool operator==(const __list_const_iterator<T>& it) const
{
return _node == it._node;
}
};*/
template<class T>
class list
{
typedef list_node<T> Node;
public:
typedef __list_iterator<T, T&, T*> iterator;
//typedef __list_const_iterator<T> const_iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
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);
}
void empty_init()
{
_head = new Node;
_head->_prev = _head;
_head->_next = _head;
}
list()
{
empty_init();
}
// lt2(lt1)
list(const list<T>& lt)
{
empty_init();
for (auto& e : lt)
{
push_back(e);
}
}
list(initializer_list<T> il)
{
empty_init();
for (auto& e : il)
{
push_back(e);
}
}
void swap(list<T>& lt)
{
std::swap(_head, lt._head);
std::swap(_size, lt._size);
}
// lt1 = lt3
/*list<T>& operator=(const list<T>& lt)
{
if (this != <)
{
clear();
for (auto& e : lt)
{
push_back(e);
}
}
return *this;
}*/
list<T>& operator=(list<T> lt)
{
swap(lt);
return *this;
}
~list()
{
/*iterator it = begin();
while (it != end())
{
it = erase(it);
}*/
clear();
delete _head;
_head = nullptr;
}
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
void push_back(const T& x)
{
/*Node* newnode = new Node(x);
Node* tail = _head->_prev;
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;*/
insert(end(), x);
}
void push_front(const T& x)
{
insert(begin(), x);
}
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
void insert(iterator pos, const T& val)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* newnode = new Node(val);
newnode->_next = cur;
newnode->_prev = prev;
prev->_next = newnode;
cur->_prev = newnode;
++_size;
}
iterator erase(iterator pos)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = next;
next->_prev = prev;
delete cur;
--_size;
//return iterator(next);
return next;
}
size_t size() const
{
/*size_t n = 0;
for (auto& e : *this)
{
++n;
}
return n;*/
return _size;
}
private:
Node* _head;
size_t _size = 0;
};
}
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "list.h"
namespace bit
{
void test_list1()
{
bit::list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
list<int>::iterator it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
struct Pos
{
int _row;
int _col;
Pos(int row = 0, int col = 0)
:_row(row)
,_col(col)
{ }
};
void test_list2()
{
bit::list<Pos> lt;
lt.push_back({ 1,1 });
lt.push_back({ 2,2 });
lt.push_back({ 3,3 });
lt.push_back({ 4,4 });
bit::list<Pos>::iterator it = lt.begin();
while (it != lt.end())
{
//cout << (*it)._row << ":" << (*it)._col << endl;
//为了可读性,这里省略了一个->
cout << it->_row << ":" << it->_col << endl;
//cout << it.operator->()->_row << ":" << it.operator->()->_col << endl;
++it;
}
cout << endl;
}
void test_list3()
{
bit::list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(3);
lt1.push_back(4);
lt1.push_front(10);
lt1.push_front(20);
list<int>::iterator it1 = lt1.begin();
while (it1 != lt1.end())
{
cout << *it1 << " ";
++it1;
}
cout << endl;
}
void test_list4()
{
bit::list<int> lt1;
lt1.push_back(1);
lt1.push_back(2);
lt1.push_back(3);
lt1.push_back(4);
list<int>::iterator it1 = lt1.begin();
while (it1 != lt1.end())
{
cout << *it1 << " ";
++it1;
}
cout << endl;
bit::list<int> lt2(lt1);
list<int>::iterator it2 = lt2.begin();
while (it2 != lt2.end())
{
cout << *it2 << " ";
++it2;
}
cout << endl;
}
template<class T>
void print(const list<T>& lt)
{
// 类模版未实例化,不能去类模板中找后面的东西
// 编译器就分不清const_iterator是内嵌类型还是静态成员变量
// typename告诉编译器,我确认过了这里是类型
//typename list<T>::const_iterator it = lt.begin();
auto it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
void test_list5()
{
list<int> lt1 = { 1,2,3,4,5 };
list<double> lt2 = { 1.1,2.2,3.3,4.4,5.5 };
print(lt1);
print(lt2);
}
}
int main()
{
bit::test_list5();
return 0;
}

被折叠的 条评论
为什么被折叠?



