1. 基本结构与文件规划
list.h头文件:包含类的全部(函数的声明与定义)
test.cpp源文件:进行调用test函数,测试和完善功能
基本结构:
#pragma oncenamespace CH
{//定义节点,采用struct,是因为struct的结构体是公有的template <class T>struct list_node{list_node<T>* _prve;list_node<T>* _next;T _val;list_node(const T& val=T()):_prve(nullptr),_next(nullptr),_val(val){}};//迭代器template <class T,class Ref,class Prt>struct list_iterator{typedef list_node<T> Node;//重命名typedef list_iterator<T, Ref ,Prt> self;//重命名Node* _node;//定义节点0//构造函数list_iterator(Node* node )//这里定义节点作为形参,因为在my_list中会传节点来初始化Ref operator* ()//换成这个,如果调用的是const类型的,就返回const类型的,不是就返回正常类型的Prt operator->()//前置++self& operator++()//返回迭代器类型//后置++self operator++(int)//返回迭代器类型//前置--self& operator--()//后置--self operator--(int)bool operator!=(const self& it)bool operator==(const self& it)};template <class T>class my_list{typedef list_node<T> Node;public:typedef list_iterator<T, T& ,T*> iterator;//如果不是const类型的就调用这个typedef list_iterator<T, const T&,const T*> const_iterator;//是const类型的调这个//迭代器iterator begin()//返回迭代器类型会调用迭代器的构造函数iterator end()const_iterator begin()constconst_iterator end()const//初始化,并且创造一个头节点void empty_init()//构造函数my_list()//拷贝构造my_list(const my_list<T>& lt)//析构函数~my_list()//交换void swap(my_list<T>& lt)//"="my_list& operator=(my_list<T> lt)//全部删除void clear()//尾插void push_back(const T& x)//头插void push_front(const T& x)//尾删void pop_back()//头删void pop_front()//插入iterator insert(iterator pos, const T& x)//返回删除之后下一个迭代器的位置//删除iterator erase(iterator pos)//返回删除之后下一个迭代器的位置//记录节点个数size_t size()private:Node* _head;//定义头节点size_t _size;//记录节点的个数};};
list_node 结构体:
- 定义了链表的节点结构,包含了三个成员变量:前驱指针
_prev
、后继指针_next
和数据_data
。 - 构造函数初始化了这些成员变量,允许在创建节点时指定初始值。
my_list
类:
- 包含了迭代器的定义、构造函数、析构函数以及一系列的操作函数。
- 定义了两种迭代器类型:
iterator
和const_iterator
,分别用于可修改的迭代和只读的迭代。 - 实现了一系列的操作函数
2. 默认函数
2.1 构造函数
我将私有变量初始化单独放在了一个函数中,以后初始化直接调用就行
//初始化
void empty_init()
{_head = new Node;//开辟头节点,并且头节点不存数据_head->_prve = _head;_head->_next = _head;_size = 0;
}//空参构造函数
my_list()
{empty_init();
}//这也是一种构造函数
my_list(size_t n,const T& x=T())
{empty_init();for(size_t i=0;i<10;i++){oush_back(x);}
}//迭代器构造
template <class Iterator>//为什么使用模版:因为可能使用其他类型的迭代器来进行初始化
my_list(Iterator first, Iterator last)
{while (first != last){push_back(*first);first++;}
}
2.2 拷贝构造
//拷贝构造
my_list(const my_list<T>& lt)
{empty_init();for (auto& x : lt)//这里用引用,因为自定义类型拷贝代价大{push_back(x);}
}
2.3 析构函数
//析构函数
~my_list()
{clear();delete _head;_head = nullptr;
}
3. 迭代器(iterator)(begin(),end())
这里为什么我们要把迭代器封装为一个类呢?明明之前模拟vector
和string
时,就直接typedef
了
迭代器从某种程度来说也可以理解为是节点的地址,返回就是返回这个节点的地址
之前模拟
vector
和string
时,二者底层都是连续的,想要到下一个可以直接++;想要得到里面的数据可以直接*
。但是现在对于
list
是不行的,我们就需要重载各种运算符,但是底层又是一个指针(内置类型)不能重载,现在就只能封装进一个类里,就能重载了
#pragma once
//#include<iostream>
//using namespace std;namespace CH
{//迭代器template <class T,class Ref,class Prt>struct list_iterator{typedef list_node<T> Node;//重命名typedef list_iterator<T, Ref ,Prt> self;//重命名Node* _node;//定义节点0//构造函数list_iterator(Node* node )//这里定义节点作为形参,因为在my_list中会传节点来初始化:_node(node){}Ref operator* ()//换成这个,如果调用的是const类型的,就返回const类型的,不是就返回正常类型的{return _node->_val;}Prt operator->(){return &_node->_val;}//前置++self& operator++()//返回迭代器类型{_node = _node->_next;return *this;}//后置++self operator++(int)//返回迭代器类型{self tmp(*this);_node = _node->_next;return tmp;}//前置--self& operator--(){_node = _node->_prve;return *this;}//后置--self operator--(int){self tmp(*this);_node = _node->_prve;return tmp;}bool operator!=(const self& it){return _node != it._node;}bool operator==(const self& it){return _node == it._node;}};template <class T>class my_list{typedef list_node<T> Node;public:typedef list_iterator<T, T& ,T*> iterator;//如果不是const类型的就调用这个typedef list_iterator<T, const T&,const T*> const_iterator;//是const类型的调这个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);}private:Node* _head;//定义头节点size_t _size;//记录节点的个数};};
4.增删改查
4.1 insert()
//插入
iterator insert(iterator pos, const T& x)//返回删除之后下一个迭代器的位置
{Node* newnode = new Node(x);//在迭代器中找到这个位置的节点Node* tmp = pos._node;Node* prve = tmp->_prve;prve->_next = newnode;newnode->_prve = prve;newnode->_next = tmp;tmp->_prve = newnode;++_size;return newnode;
}
4.2 push_back()和push_front()
//尾插
void push_back(const T& x)
{insert(end(), x);
}//头插
void push_front(const T& x)
{insert(begin(), x);
}
4.3 erase()
//删除
iterator erase(iterator pos)//返回删除之后下一个迭代器的位置
{Node* tmp = pos._node;//在迭代器中找到这个位置的节点Node* prve = tmp->_prve;Node* next = tmp->_next;prve->_next = next;next->_prve = prve;delete tmp;--_size;return next;
}
4.3 pop_back()和pop_front()
//尾删
void pop_back()
{erase(--end());
}//头删
void pop_front()
{erase(begin());
}
5. 其他函数
5.1 swap()和clear()
//交换
void swap(my_list<T>& lt)
{std::swap(_head, lt._head);std::swap(_size, lt._size);
}//全部删除
void clear()
{iterator it = begin();while (it != end()){it=erase(it);}_size = 0;
}
5.2 size()和"="
//"="
my_list& operator=(my_list<T> lt)
{swap(lt);return *this;
}//节点个数
size_t size()
{return _size;
}
7. 全部代码
list.h
#pragma oncenamespace CH
{//定义节点,采用struct,是因为struct的结构体是公有的template <class T>struct list_node{list_node<T>* _prve;list_node<T>* _next;T _val;list_node(const T& val=T()):_prve(nullptr),_next(nullptr),_val(val){}};//迭代器template <class T,class Ref,class Prt>struct list_iterator{typedef list_node<T> Node;//重命名typedef list_iterator<T, Ref ,Prt> self;//重命名Node* _node;//定义节点0//构造函数list_iterator(Node* node )//这里定义节点作为形参,因为在my_list中会传节点来初始化:_node(node){}Ref operator* ()//换成这个,如果调用的是const类型的,就返回const类型的,不是就返回正常类型的{return _node->_val;}Prt operator->(){return &_node->_val;}//前置++self& operator++()//返回迭代器类型{_node = _node->_next;return *this;}//后置++self operator++(int)//返回迭代器类型{self tmp(*this);_node = _node->_next;return tmp;}//前置--self& operator--(){_node = _node->_prve;return *this;}//后置--self operator--(int){self tmp(*this);_node = _node->_prve;return tmp;}bool operator!=(const self& it){return _node != it._node;}bool operator==(const self& it){return _node == it._node;}};template <class T>class my_list{typedef list_node<T> Node;public:typedef list_iterator<T, T& ,T*> iterator;//如果不是const类型的就调用这个typedef list_iterator<T, const T&,const T*> const_iterator;//是const类型的调这个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->_prve = _head;_head->_next = _head;_size = 0;}//构造函数,并且创造一个头节点my_list(){empty_init();}//拷贝构造my_list(const my_list<T>& lt){empty_init();for (auto& x : lt){push_back(x);}}//析构函数~my_list(){clear();delete _head;_head = nullptr;}//交换void swap(my_list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}//"="my_list& operator=(my_list<T> lt){swap(lt);return *this;}//全部删除void clear(){iterator it = begin();while (it != end()){it=erase(it);}_size = 0;}//尾插void push_back(const T& x){//Node* newnode = new Node(x);//Node* tmp = _head->_prve;//找到头节点的前一个,也就是最后一个节点//tmp->_next = newnode;//newnode->_prve = tmp;//newnode->_next = _head;//_head->_prve = newnode;//++_size;insert(end(), x);}//头插void push_front(const T& x){insert(begin(), x);}//尾删void pop_back(){erase(--end());}//头删void pop_front(){erase(begin());}//插入iterator insert(iterator pos, const T& x)//返回删除之后下一个迭代器的位置{Node* newnode = new Node(x);//在迭代器中找到这个位置的节点Node* tmp = pos._node;Node* prve = tmp->_prve;prve->_next = newnode;newnode->_prve = prve;newnode->_next = tmp;tmp->_prve = newnode;++_size;return newnode;}//删除iterator erase(iterator pos)//返回删除之后下一个迭代器的位置{Node* tmp = pos._node;//在迭代器中找到这个位置的节点Node* prve = tmp->_prve;Node* next = tmp->_next;prve->_next = next;next->_prve = prve;delete tmp;--_size;return next;}size_t size(){return _size;}private:Node* _head;//定义头节点size_t _size;//记录节点的个数};
};