总述
list模拟实现主要包括四个类:节点类、迭代器类、反向迭代器类、list类。
list底层结构:

因为list的底层空间不连续,所以迭代器不能使用原生态的指针,将节点类型的指针封装成类,重载解引用及自增等常用操作。list可以保存多种数据类型,所以这些类都写成类模板
一、节点类
list底层是带头结点的双向循环链表,先实现节点类,给成类模板的形式,便于插入不同类型的数据。
- template<class T>
- struct ListNode
- {
- ListNode<T>* prev;
- ListNode<T>* next;
- T data;//要在链表中保存的数据类型
-
- ListNode(const T& value = T())
- :prev(nullptr)
- , next(nullptr)
- , data(value)
- { }
- };
定义新节点的方法:
- ListNode<变量类型>*变量名=new ListNode(value);
二、迭代器类
迭代器类模板有三个参数
- T:迭代器指向的元素类型
- Ref:返回的引用类型
- Ptr:返回的指针类型
Ref和Ptr一般不写成T&和T*。

成员变量
迭代器类的成员变量就是节点类型的指针
- Node* _pNode;//成员变量,节点类型指针
构造函数
编译器默认的构造函数是无参的,构造函数需要给出
- ListIterator(Node* pNode = nullptr)
- :_pNode(pNode)
- {}
*重载
返回节点中保存的数据
- Ref operator*()
- {
- return _pNode->data;
- }
->重载
返回节点中保存的数据的地址
- Ptr operator->()
- {
- return &_pNode->data;
- }
->的重载只对内置类型有意义:

“++”
前置++
返回值是迭代器自身类型的引用,前面已经将ListIterator<T, Ref, Ptr>重命名位Self,表示迭代器自身的类型。
- 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& it)
- {
- return _pNode != it._pNode;
- }
- bool operator==(const Self& it)
- {
- return _pNode == it._pNode;
- }
三、反向迭代器类
反向迭代器可以对迭代器类进行复用

因为类外访问静态成员变量时也会使用类名::变量名的方式,所以对迭代器类中的Reference和Pointer进行重命名时要加上typename,明确告诉编译器要重命名的是一个数据类型。否则编译器会报错:

成员变量
反向迭代器对迭代器类进行复用
- private:
- Iterator _it;//正向迭代器
*重载
反向迭代器的解引用要做特殊处理,返回的是对迭代器–的值
- Reference operator*()
- {
- //*做特殊处理,先--,再解引用返回
- auto temp = _it;
- --temp;
- return *temp;
- }
->重载
复用*的重载,返回value的地址
- Pointer operator->()
- {
- return &(operator*());
- }
“++”
反向迭代器的++即为正向迭代器的–
- Self operator++()
- {
- --_it;
- return *this;
- }
- Self operator++(int)
- {
- Self temp(*this);
- --_it;
- return *this;
- }
“- -”
反向迭代器的–用正向迭代器的++替代
- Self operator--()
- {
- ++_it;
- return *this;
- }
- Self operator--(int)
- {
- Self temp(*this);
- ++_it;
- return temp;
- }
" == " 和"!="
比较反向迭代器类中保存的正向迭代器,复用正向迭代器中的比较方法
- bool operator==(const Self& rit)
- {
- return _it == rit;
- }
- bool operator!=(const Self& rit)
- {
- return _it == rit._it;
- }
四、list类

成员变量
list的成员变量只有一个head指针,指向链表的第一个节点
构造相关
空对象
创造头节点的方法:
- //提供一个创造头结点的方法
- void CreatHead()
- {
- //调用节点类的构造方法
- head = new Node();
- head->next = head;
- head->prev = head;
- }
- 0000000
new申请空间,令head指向这段空间,head的next和prev都指向自己。
n个T类型元素
调用push_back方法,创造头节点后,不断进行尾插直到元素个数等于n
- list(int n, const T& value = T())
- {
- CreatHead();
- for (int i = 0; i < n; ++i)
- {
- push_back(value);
- }
- }
拷贝构造
复用push_back
- list(const list<T>& l)
- {
- CreatHead();
- auto it = l.cbegin();
- while (it != l.cend())
- {
- push_back(*it);
- it++;
- }
- }
迭代器构造
将迭代器构造方法写成函数模板,可以传入不同类型的迭代器来构造list对象
- template<class InputIterator>
- list(InputIterator first, InputIterator last)
- {
- CreatHead();
- while (first != last)
- {
- push_back(*first);
- first++;
- }
- }
赋值运算符重载
与拷贝构造写法相同
- list<T>& operator=(const list<T>& l)
- {
- if (this != &l)
- {
- clear();//先清空当前对象中的节点
- auto it = l.cbegin();
- while (it != l.cend())
- {
- push_back(*it);
- it++;
- }
- }
- return *this;
- }
析构
清空当前对象,释放头节点空间,将头节点置空
- ~list()
- {
- clear();
- delete head;
- head = nullptr;
- }
迭代器
正向迭代器
begin
此处的iterator是对ListIterator<T, T&, T*>的重命名,这里会返回一个ListIterator<T, T&, T*>类对象
- iterator begin()
- {
- //iterator it(head->next);
- //return it;
- //head->next是传递给迭代器类对象构造函数的参数,调用iterator的构造函数
- return iterator(head->next);//构造匿名对象返回
- }
end
- iterator end()
- {
- return iterator(head);
- }
const类型迭代器
iterator和const_iterator 是两个不同的类:

两者使用的是相同的类模板,但是传递的参数不同,最终实例化的也是不同的类。
cbegin&cend
- const_iterator cbegin()const
- {
- return const_iterator(head->next);
- }
- const_iterator cend()const
- {
- return const_iterator(head);
- }
反向迭代器
rbegin&rend
返回正向迭代器的end和begin
- reverse_iterator rbegin()
- {
- ?? ?return reverse_iterator(end());
- }
- reverse_iterator rend()
- {
- ?? ?return reverse_iterator(begin());
- }
crbegin&crend
复用正向迭代器的cend和cbegin
- const_reverse_iteraotr crbegin()const
- {
- ?? ?return const_reverse_iteraotr(cend());
- }
- const_reverse_iteraotr crend()const
- {
- ?? ?return const_reverse_iteraotr(cbegin());
- }
容量操作
size
遍历链表,统计节点个数
- size_t size()
- {
- ?? ?auto it = cbegin();
- ?? ?size_t count = 0;
- ?? ?while (it != cend())
- ?? ?{
- ?? ??? ?++count;
- ?? ??? ?++it;
- ?? ?}
- ?? ?return count;
- }
empty
如果head->next是head本身则表明链表为空
- bool empty()
- {
- ?? ?return head->next == head;
- }
resize
改变节点个数,若新的节点个数大于旧的,则调用push_back填充元素;若新的节点个数小于原来的调用pop_back尾删

元素访问
front
复用迭代器解引用的方法,返回begin()位置元素
- T& front()
- {
- return *begin();
- }
- const T& front()const
- {
- return *cbegin();
- }
back
back表示最后一个元素,但是end()指向的是最后一个元素的下一个位置,需要定义临时变量,不能直接对end()进行- -。
- T& back()
- {
- auto it = end();
- //return --end()//错误写法
- it--;
- return *it;
- }
- const T& back()const
- {
- auto it = end();
- it--;
- return *it;
- }
打印链表
定义一个打印链表的函数模板,检验方法。通过迭代器遍历链表,打印每一个节点的数据。
- template<class T>
- void PrintList(const list<T>& l)
- {
- auto it = l.cbegin();
- while (it != l.cend())
- {
- cout << *it << " ";
- ++it;
- }
- cout << endl;
- }
元素修改
尾插与尾删
push_back
复用insert方法在end位置插入
- void push_back(const T& value)
- {
- insert(end(), value);
- }
pop_back
先判断链表是否为空,复用erase方法在end的前一个位置进行插入
- void pop_back()
- {
- if (empty())
- {
- return;
- }
- auto it = end();
- it--;
- erase(it);
- }
头插与头删
复用insert与erase方法,在begin()位置进行插入或删除
- void push_front(const T& value = T())
- {
- insert(begin(), value);
- }
- void pop_front()
- {
- erase(begin());
- }
?insert
任意位置的插入:申请新节点,连接新节点与链表,断开旧的连接。
这里传入的参数是一个迭代器类对象,不能直接进行操作,要对对象中封装的_pNode指针进行操作。
返回值是新插入的节点的迭代器,所以要用申请的新节点的指针newnode构造一个迭代器类对象返回,不能直接返回newnode
- iterator insert(iterator Insertpos, const T& value)
- {
- Node* newnode = new Node(value);
- Node* pos = Insertpos._pNode;//_pNode是节点类型的指针
- newnode->next = pos;
- newnode->prev = pos->prev;
- newnode->prev->next = newnode;
- pos->prev = newnode;
- //return newnode;
- //?迭代器是封装的Node*指针,此时不能再返回newnode
- return iterator(newnode);//构造匿名对象返回
- }
?erase
任意位置的删除:分别改变前后两个节点的next和prev指针的指向即可
- iterator erase(iterator Erasepos)
- {
- Node* pos = Erasepos._pNode;
- Node* ret = pos->next;
- pos->prev->next = pos->next;
- pos->next->prev = pos->prev;
- delete pos;
- return iterator(ret);
- }
区间删除:复用单个节点删除的方法,遍历要删除的区间。
要用接收erase的返回值,防止迭代器失效
- iterator erase(iterator first, iterator last)
- {
- auto it = first;
- while (it != last)
- {
- //it=erase(it);
- //后置++会构造临时对象返回,不会导致迭代器失效
- erase(it++);
- }
- return it;
- }
clear&swap
- clear复用erase区间删除的方法,从begin删除到end位置;
- swap方法调用标准库中的swap,交换两个链表的头节点。
- void clear()
- {
- erase(begin(), end());
- }
- void swap(list<T>& l)
- {
-
- std::swap(head, l.head);
- }
附:完整list类,含测试用例
- #include<iostream>
- #include<vector>
- using namespace std;
-
- namespace ZH
- {
- /
- //节点类模板,
- template<class T>
- struct ListNode
- {
- ListNode<T>* prev;
- ListNode<T>* next;
- T data;
-
- ListNode(const T& value = T())
- :prev(nullptr)
- , next(nullptr)
- , data(value)
- { }
- };
-
- /
- //迭代器类模板
- //list的迭代器不能使用原生态的指针,要进行封装
- //T:迭代器指向的元素类型
- //Ref:给operator*使用,返回引用类型,不要写成T&
- //Ptr:返回值使用,不要写成T*
- template<class T,class Ref,class Ptr>
- class ListIterator
- {
- public:
- typedef ListNode<T> Node;//化简节点类的名字
- typedef Ref Reference;//在反向迭代器类中使用
- typedef Ptr Pointer;
-
- typedef ListIterator<T, Ref, Ptr> Self;//简化迭代器类的名字
-
- //构造函数
- ListIterator(Node* pNode=nullptr)
- :_pNode(pNode)
- {}
-
- //重载部分需要使用的运算符即可:*、->、++、--、==
- Ref operator*()
- {
- return _pNode->data;
- }
- //T为自定义类型时有意义,
- Ptr operator->()
- {
- return &_pNode->data;
- }
- //前置++,返回值是迭代器自身类型的引用
- 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& it)
- {
- return _pNode != it._pNode;
- }
- bool operator==(const Self& it)
- {
- return _pNode == it._pNode;
- }
-
- Node* _pNode;//成员变量,节点类型指针
- };
-
-
- //反向迭代器类模板,对迭代器进行复用
- template<class Iterator>
- class ListReverseIterator
- {
- public:
- //typedef Iterator::Reference Reference;
- //typedef Iterator::Pointer Pointer;
- typedef typename Iterator::Reference Reference;//typename指定Reference是Iterator中的数据类型
- typedef typename Iterator::Pointer Pointer;
- typedef ListReverseIterator<Iterator> Self;
-
- ListReverseIterator(Iterator it)
- : _it(it)
- { }
-
- Reference operator*()
- {
- //*做特殊处理,先--,再解引用返回
- auto temp = _it;
- --temp;
- return *temp;
- }
- Pointer operator->()
- {
- return &(operator*());
- }
- Self operator++()
- {
- --_it;
- return *this;
- }
- Self operator++(int)
- {
- Self temp(*this);
- --_it;
- return *this;
- }
- Self operator--()
- {
- ++_it;
- return *this;
- }
- Self operator--(int)
- {
- Self temp(*this);
- ++_it;
- return temp;
- }
- bool operator==(const Self& rit)
- {
- return _it == rit;
- }
- bool operator!=(const Self& rit)
- {
- return _it == rit._it;
- }
-
- private:
- Iterator _it;//正向迭代器
- };
-
- template<class T>
- class list
- {
- typedef ListNode<T> Node;
- //typedef Node* iterator;//不能使用Node*作迭代器
- //迭代器
- typedef ListIterator<T, T&, T*> iterator;
- typedef ListIterator< T, const T&, const T*> const_iterator;
-
- typedef ListReverseIterator<iterator> reverse_iterator;
- typedef ListReverseIterator<const_iterator> const_reverse_iteraotr;
-
- public:
- ///
- //构造
- list()
- {
- CreatHead();
- }
- list(int n, const T& value=T())
- {
- CreatHead();
- for (int i = 0; i < n; ++i)
- {
- push_back(value);
- }
- }
- list(const list<T>& l)
- {
- CreatHead();
- auto it = l.cbegin();
- while (it != l.cend())
- {
- push_back(*it);
- it++;
- }
- }
- //迭代器区间构造
- template<class InputIterator>
- list(InputIterator first, InputIterator last)
- {
- CreatHead();
- while (first != last)
- {
- push_back(*first);
- first++;
- }
- }
- //赋值运算符重载
- list<T>& operator=(const list<T>& l)
- {
- if (this != &l)
- {
- clear();//先清空当前对象中的节点
- auto it = l.cbegin();
- while (it != l.cend())
- {
- push_back(*it);
- it++;
- }
- }
- return *this;
- }
- ~list()
- {
- clear();
- delete head;
- head = nullptr;
- }
- public:
- //迭代器
- iterator begin()
- {
- //iterator it(head->next);
- //return it;
- //iterator是对ListIterator<T, T&, T*>的重命名
- //这里会返回一个ListIterator<T, T&, T*>类对象
- //head->next是传递给迭代器类对象构造函数的参数,调用iterator的构造函数
- return iterator(head->next);//构造匿名对象返回
- }
- iterator end()
- {
- return iterator(head);
- }
- //const类型迭代器
- const_iterator cbegin()const
- {
- return const_iterator(head->next);
- }
- const_iterator cend()const
- {
- return const_iterator(head);
- }
-
- //反向迭代器
- //反向迭代器的成员变量是一个迭代器类对象
- //end()即为传递给反向迭代器类构造函数的参数
- reverse_iterator rbegin()
- {
- return reverse_iterator(end());
- }
- reverse_iterator rend()
- {
- return reverse_iterator(begin());
- }
- //反向const类型迭代器
- const_reverse_iteraotr crbegin()const
- {
- return const_reverse_iteraotr(cend());
- }
- const_reverse_iteraotr crend()const
- {
- return const_reverse_iteraotr(cbegin());
- }
-
- /
- //容量
- size_t size()
- {
- auto it = cbegin();
- size_t count = 0;
- while (it != cend())
- {
- ++count;
- ++it;
- }
- return count;
- }
- bool empty()
- {
- return head->next == head;
- }
- void resize(int newsize,const T& value=T())
- {
- size_t oldsize = size();
- if (newsize > oldsize)
- {
- while (oldsize++<newsize)
- {
- push_back(value);
- }
- }
- if (newsize < oldsize)
- {
- while (oldsize-- < newsize)
- {
- pop_back();
- }
- }
- }
-
- ///
- //元素访问
- T& front()
- {
- return *begin();
- }
- const T& front()const
- {
- return *cbegin();
- }
- T& back()
- {
- auto it = end();
- it--;
- return *it;
- }
- const T& back()const
- {
- auto it = end();
- it--;
- return *it;
- }
-
-
- /
- //元素修改
- void push_back(const T& value)
- {
- insert(end(), value);
- }
-
- void pop_back()
- {
- if (empty())
- {
- return;
- }
- auto it = end();
- it--;
- erase(it);
- }
- void push_front(const T& value = T())
- {
- //Node* pos = head->next;
- /*Node* newnode = new Node(value);
- newnode->next = head->next;
- newnode->prev = head;
- head->next->prev = newnode;
- head->next = newnode;*/
- //复用insert
- insert(begin(), value);
- }
- void pop_front()
- {
- erase(begin());
- }
-
- //?insert
- // iterator是ListIterator<T, T&, T*>
- iterator insert(iterator Insertpos, const T& value)
- {
- Node* newnode = new Node(value);
- Node* pos = Insertpos._pNode;//_pNode是节点类型的指针
- newnode->next = pos;
- newnode->prev = pos->prev;
- newnode->prev->next = newnode;
- pos->prev = newnode;
- //return newnode;
- //?迭代器是封装的Node*指针,此时不能再返回newnode
- return iterator(newnode);//构造匿名对象返回
- }
- //?erase
- iterator erase(iterator Erasepos)
- {
- Node* pos = Erasepos._pNode;
- Node* ret = pos->next;
- pos->prev->next = pos->next;
- pos->next->prev = pos->prev;
- delete pos;
- return iterator(ret);
- }
- iterator erase(iterator first, iterator last)
- {
- auto it = first;
- while (it != last)
- {
- //it=erase(it);
- erase(it++);
- }
- return it;
- }
-
- void clear()
- {
- erase(begin(), end());
- }
- void swap(list<T>& l)
- {
- std::swap(head, l.head);
- }
-
- private:
- //提供一个创造头结点的方法
- void CreatHead()
- {
- //调用节点类的构造方法
- head = new Node();
- head->next = head;
- head->prev = head;
- }
- private:
- Node* head;
-
- };
-
- template<class T>
- void PrintList(const list<T>& l)
- {
- auto it = l.cbegin();
- while (it != l.cend())
- {
- cout << *it << " ";
- ++it;
- }
- cout << endl;
- }
- }
-
- void Test1()
- {
- ZH::list<int> l1;
- ZH::list<int> l2(3, 1);
- PrintList(l2);
- ZH::list<int> l3(l2.begin(), l2.end());
- PrintList(l3);
- vector<int> v{ 0,1,2,3,4 };
- ZH::list<int> l4(v.begin(), v.end());
- PrintList(l4);
- }
-
- void Test2()
- {
- vector<int> v{ 1,2,3,4 };
- ZH::list<int> L1(v.begin(), v.end());
- L1.push_back(5);
- L1.push_back(6);
- L1.push_front(0);
- PrintList(L1);
- L1.pop_back();
- L1.pop_front();
- PrintList(L1);
- L1.erase(--L1.end());
- PrintList(L1);
- }
-
- void Test3()
- {
- ZH::list<int> L1;
- L1.push_back(1);
- L1.push_back(2);
- L1.push_back(3);
- L1.push_front(0);
- PrintList(L1);
- L1.resize(6, 5);
- PrintList(L1);
- }
-
- struct A
- {
- int a;
- int b;
- int c;
- };
-
- void Test4()
- {
- A aa{ 1,2,3 };
- A bb{ 4,5,6 };
- A cc{ 7,8,9 };
- ZH::list<A> L;
- L.push_back(aa);
- L.push_back(bb);
- L.push_back(cc);
- auto it = L.begin();
- while (it != L.end())
- {
- //?it->得到的是节点的地址
- //本应是it->->a,编译器做了特殊处理
- cout << it->a << " ";
- it++;
- }
- cout << endl;
- }
-
- void Test5()
- {
- ZH::list<int> L1;
- L1.push_back(0);
- L1.push_back(1);
- L1.push_back(2);
- L1.push_back(3);
- PrintList(L1);
- cout << L1.back() << endl;
- cout << L1.front() << endl;
- cout << L1.size() << endl;
- L1.clear();
- cout << L1.size() << endl;
- }
- void Test6()
- {
- ZH::list<int> L1;
- L1.push_back(0);
- L1.push_back(1);
- L1.push_back(2);
- L1.push_back(3);
- PrintList(L1);
- //区间删除
- /*L1.erase(L1.begin(), L1.end());
- PrintList(L1);*/
-
- ZH::list<int> L2;
- L2.push_back(1);
- L2.push_back(2);
- L2.push_back(3);
- L2.push_back(4);
- L2.push_back(5);
- PrintList(L2);
- L1.swap(L2);
- PrintList(L1);
- PrintList(L2);
- }
-
- int main()
- {
- Test6();
- system("pause");
- return 0;
- }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持w3xue。