一 定义节点类
list相当于带头节点的双向链表,我们定义节点时要用类模板参数,同时定义_next、_prev指针和数据_data,使用struct定义节点类,因为节点类要能够被访问,而struct的默认访问权限就是public(当然手动更改权限为public也可),构造函数缺省值要使用匿名对象,保证无论是自定义类型还是内置类型都能够构造成功。
cpp
template<class T>
struct list_node
{
T _data;
list_node<T>* _next;
list_node<T>* _prev;
list_node(const T& x = T())
:_data(x)
,_next(nullptr)
,_prev(nullptr)
{}
};
二 list的基本框架
list是带头节点的双向链表,所以成员变量我们只需要定义一个头结点_head
,但是链表的长度我们无法像vector一样通过指针的加减法进行求取,因此我们加入一个size变量进行对链表长度的求取。
默认构造函数则就是让头节点指向自己,但是list不只有一个构造函数,所以我们讲头节点指向自己这一部分单独封装为一个函数,从而让更多构造函数使用。
代码实现如下:
cpp
template<class T>
class list {
typedef list_node<T> Node;
public:
list() {
empty_init();
}
void empty_init(){
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
_size = 0;
}
private:
Node* _head;
size_t _size;
};
三 list的迭代器
vector和string的底层物理空间是连续的,我们可以通过指针的++或--来移动找到对应的元素,然而list的底层物理空间是不连续的,所以模拟实现list迭代器时,如果使用++或 --操作,++或 --的只是一个指针,并不能找到对应的位置。因此我们可以封装一个list迭代器类,实际上就是对结点指针进行封装,将各种运算符进行重载,使得在list类中能够像vector和string一样能够直接使用迭代器,而不用关心底层实现。
但注意,我们的迭代器分为const迭代器和非const迭代器,莫非我们需要写两个迭代器吗?我们都知道两个迭代器的区别:
const_iterator不允许您更改它们指向的值,常规iterator可以。
显然,两个迭代器只有在外部进行修改的时候有所不同,在内部实现并没有什么差别,因此我们可以复用一个模板,但需要三个模板参数,在list内部我们传入T ,T* ,T& 或者是 T ,const T*, const T&,这样就可以保持两个迭代器的区别,并且可以复用同一段代码。
3.1 普通迭代器的实现
代码在list内部如下定义:
cpp
template<class T>
class list {
typedef list_node<T> Node;
public:
//区分两个迭代器
typedef __list_iterator<T, T&, T*> iterator;
list() {
empty_init();
}
void empty_init(){
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
_size = 0;
}
private:
Node* _head;
};
迭代器代码:
cpp
// 三个模板参数
// T T& T*
// T cosnt T& const T*
template<class T, class Ref, class Ptr>
struct __list_iterator{
typedef list_node<T> Node;
typedef __list_iterator<T, Ref, Ptr> self;
Node* _node;
//用一个节点创造iterator
__list_iterator(Node* node)
:_node(node)
{}
self& operator++(){
_node = _node->_next;
return *this;
}
self& operator--(){
_node = _node->_prev;
return *this;
}
self operator++(int){
self tmp(*this);
_node = _node->_next;
return tmp;
}
self operator--(int){
self tmp(*this);
_node = _node->_prev;
return tmp;
}
Ref operator*(){
return _node->_data;
}
Ptr operator->(){
return &_node->_data;
}
bool operator!=(const self& s){
return _node != s._node;
}
bool operator==(const self& s){
return _node == s._node;
}
};
当我们实现上述代码之后我们就可以在list类中实现begin和end函数:
cpp
iterator begin()
{
//也可以写成这样的形式
// return _head->next 通过返回值自动构造
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
3.2 const迭代器的实现
cpp
template<class T>
class list {
typedef list_node<T> Node;
public:
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
//将begin和end函数补全
const_iterator begin() const
{
//返回的是const迭代器类型,避免在外部修改数据
return const_iterator(_head->_next);
}
const_iterator end() const
{
return const_iterator(_head);
}
四 list的常用接口模拟实现
链表中只要实现了insert和erase,头插头删和尾插尾删都可以实现,所以我们先实现insert和erase函数。
4.1 insert函数
在pos位置之前插入一个新结点。
借用双链表的思想实现即可。
ps:传入的值为返回值方便复用其它函数。
cpp
//在pos位置之前插入一个新结点
iterator insert(iterator pos, const T& val){
Node* cur = pos._node;
Node* newnode = new Node(val);
Node* prev = cur->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
++_size;
//返回当前节点位置
return iterator(newnode);
}
4.2 push_back()
尾插
直接复用insert即可
cpp
void push_back(const T& x)
{
insert(end(), x);
}
4.3 push_front()
头插
直接复用insert
cpp
//头插
void push_front(const T& x){
insert(begin(), x);
}
4.4 erase() 函数
删除pos位置的结点。
cpp
iterator erase(iterator pos) {
//头节点不能删除
assert(pos != _head);
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
delete cur;
prev->_next = next;
next->_prev = prev;
--_size;
return iterator(next);
}
注意迭代器失效问题,这里需要返回值。
4.5 pop_back()
尾删
cpp
void pop_back(){
//注意这里定义的end节点位置
erase(--end());
}
4.6 pop_front()
头删
cpp
void pop_front()
{
erase(begin());
}
五 容量接口
5.1 size函数
返回节点个数。
直接返回size大小即可。
cpp
size_t size() const {
return _size;
}
5.2 clear函数
清空list
复用erase即可
cpp
void clear(){
iterator it = begin();
while (it != end()){
it = erase(it);
}
}
六 函数补全
6.1 构造函数
cpp
//拷贝构造
list(const list<T>& lt) {
empty_init();
for (auto e : it) {
push_back(e);
}
}
void swap(list<T>& lt) {
std::swap(lt._head, _head);
std::swap(lt._size, _size);
}
//移动构造
list(list<T>&& lt) {
swap(lt);
}
//迭代器区间构造函数
template<class Iterator>
list(Iterator first, Iterator last)
{
empty_init();
while (first != last)
{
push_back(*first);
++first;
}
}
6.2 赋值重载
cpp
//赋值重载
list<T>& operator()(const list<T>& lt) {
list<T> tmp(lt);
swap(tmp);
return *this;
}
//移动赋值
list<T>& operator()(list<T>&& lt) {
swap(it);
return *this;
}
6.3 析构函数
复用clear函数,记得delete head节点,并且置空。
cpp
~list(){
clear();
delete _head;
_head = nullptr;
}
七 完整代码+ 测试代码
cpp
#pragma once
#include<iostream>
#include<cassert>
#include<vector>
#include<set>
using namespace std;
namespace My {
template<class T>
struct list_node
{
T _data;
list_node<T>* _next;
list_node<T>* _prev;
list_node(const T& x = T())
:_data(x)
, _next(nullptr)
, _prev(nullptr)
{}
};
// 三个模板参数
// T T& T*
// T cosnt T& const T*
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)
{}
self& operator++(){
_node = _node->_next;
return *this;
}
self& operator--(){
_node = _node->_prev;
return *this;
}
self operator++(int){
self tmp(*this);
_node = _node->_next;
return tmp;
}
self operator--(int){
self tmp(*this);
_node = _node->_prev;
return tmp;
}
Ref operator*(){
return _node->_data;
}
Ptr operator->(){
return &_node->_data;
}
bool operator!=(const self& s){
return _node != s._node;
}
bool operator==(const self& s){
return _node == s._node;
}
};
template<class T>
class list {
typedef list_node<T> Node;
public:
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
//将begin和end函数补全
const_iterator begin() const
{
return const_iterator(_head->_next);
}
const_iterator end() const
{
return const_iterator(_head);
}
iterator begin()
{
//也可以写成这样的形式
// return _head->next 通过返回值自动构造
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
//默认构造
list() {
empty_init();
}
//拷贝构造
list(const list<T>& lt) {
empty_init();
for (auto e : lt) {
push_back(e);
}
}
void swap(list<T>& lt) {
std::swap(lt._head, _head);
std::swap(lt._size, _size);
}
//移动构造
list(list<T>&& lt) {
swap(lt);
}
//迭代器区间构造函数
template<class Iterator>
list(Iterator first, Iterator last)
{
empty_init();
while (first != last)
{
push_back(*first);
++first;
}
}
//赋值重载
list<T>& operator=(const list<T>& lt) {
list<T> tmp(lt);
swap(tmp);
return *this;
}
//移动赋值
list<T>& operator=(list<T>&& lt) {
swap(lt);
return *this;
}
void empty_init(){
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
_size = 0;
}
//在pos位置之前插入一个新结点
iterator insert(iterator pos, const T& val){
Node* cur = pos._node;
Node* newnode = new Node(val);
Node* prev = cur->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
++_size;
//返回当前节点位置
return iterator(newnode);
}
void push_back(const T& x){
insert(end(), x);
}
//头插
void push_front(const T& x){
insert(begin(), x);
}
iterator erase(iterator pos) {
//头节点不能删除
assert(pos != _head);
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
delete cur;
prev->_next = next;
next->_prev = prev;
--_size;
return iterator(next);
}
~list(){
clear();
delete _head;
_head = nullptr;
}
void pop_back(){
//注意这里定义的end节点位置
erase(--end());
}
void pop_front()
{
erase(begin());
}
void clear(){
iterator it = begin();
while (it != end()){
it = erase(it);
}
}
size_t size() const {
return _size;
}
private:
Node* _head;
size_t _size;
};
void test_list1()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
// 封装屏蔽底层差异和实现细节
// 提供统一的访问修改遍历方式
list<int>::iterator it = lt.begin();
while (it != lt.end())
{
*it += 20;
cout << *it << " ";
++it;
}
cout << endl;
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
void test_list2()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
list<int> lt1(lt);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
list<int> lt2;
lt2.push_back(10);
lt2.push_back(200);
lt2.push_back(30);
lt2.push_back(40);
lt2.push_back(50);
lt1 = lt2;
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
for (auto e : lt2)
{
cout << e << " ";
}
cout << endl;
for (auto e : lt1)
{
e++;
cout << e << " ";
}
cout << endl;
for (auto e : lt2)
{
cout << e << " ";
}
cout << endl;
}
struct AA
{
AA(int a1 = 0, int a2 = 0)
:_a1(a1)
, _a2(a2)
{}
int _a1;
int _a2;
};
void test_list3()
{
list<AA> lt;
lt.push_back(AA(1, 1));
lt.push_back(AA(2, 2));
lt.push_back(AA(3, 3));
list<AA>::iterator it = lt.begin();
while (it != lt.end())
{
cout << it->_a1 << " " << it->_a2 << endl;
cout << it.operator->()->_a1 << " " << it.operator->()->_a1 << endl;
++it;
}
cout << endl;
}
template<typename Container>
void print_container(const Container& con)
{
typename Container::const_iterator it = con.begin();
while (it != con.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
void test_list4()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
//print_list(lt);
print_container(lt);
list<string> lt1;
lt1.push_back("1111111111111");
lt1.push_back("1111111111111");
lt1.push_back("1111111111111");
lt1.push_back("1111111111111");
lt1.push_back("1111111111111");
//print_list(lt1);
print_container(lt1);
vector<string> v;
v.push_back("222222222222222222222");
v.push_back("222222222222222222222");
v.push_back("222222222222222222222");
v.push_back("222222222222222222222");
//print_list(v);
print_container(v);
}
}