C++初阶:适合新手的手撕list(模拟实现list)
1. 基本结构与文件规划
list.h头文件:包含类的全部(函数的声明与定义)
test.cpp源文件:进行调用test函数,测试和完善功能
基本结构:
#pragma once
namespace 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()const
const_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 once
namespace 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;//记录节点的个数
};
};
原文地址:https://blog.csdn.net/weixin_70067429/article/details/142450854
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!