目录
🎏双向迭代器(Bidirectional Iterator)
🎏随机迭代器(Random Access Iterator)
一.了解项目及其功能
📌了解list官方标准
了解模拟实现list
📌了解更底层的list实现
二.list迭代器和vector迭代器的异同
📌迭代器的分类
🎏单向迭代器(Forward Iterator)
🎏双向迭代器(Bidirectional Iterator)
🎏随机迭代器(Random Access Iterator)
📌list和vector的底层实现差异对迭代器的影响
三.逐步实现项目功能模块及其逻辑详解
通过第一部分对项目功能的介绍,我们已经对list的功能有了大致的了解,虽然看似需要实现的功能很多,貌似一时间不知该如何下手,但我们可以分步分模块来分析这个项目的流程,最后再将各部分进行整合,所以大家不用担心,跟着我一步一步分析吧!
📌分析list的组成结构
📌实现list结点类模板
🎏构造list结点类成员变量
🎏实现list结点类构造函数
📌实现list迭代器类模板
🎏构造list迭代器类成员变量
🎏实现list迭代器类构造函数
🎏实现operator*重载函数
🎏实现前置operator++重载函数
🎏实现后置operator++重载函数
🎏实现前置operator--重载函数
🎏实现后置operator--重载函数
🎏实现operator!=重载函数
🎏实现operator==重载函数
🎏实现operator->重载函数
🎏实现const修饰的list迭代器类模板
📌实现list类模板
🎏构造list类成员变量
🎏实现list类empty_init()函数
🎏实现list类无参构造函数
🎏实现list类拷贝构造函数
🎏实现list类swap()函数
🎏实现list类operator=()函数
🎏实现list类clear()函数
🎏实现list类析构函数
🎏实现list类begin()函数
🌳实现普通list类的begin()函数
🌳实现const修饰list类的begin()函数
🎏实现list类end()函数
🌳实现普通list类的end()函数
🌳实现const修饰list类的end()函数
🎏实现list类insert()函数
🎏实现list类erase()函数
🎏实现list类push_front()函数
🎏实现list类pop_front()函数
🎏实现list类push_back()函数
🎏实现list类pop_back()函数
🎏实现list类size()函数
四.项目完整代码
test.cpp文件
//仅测试list功能用
#include"STL_List.h"
int main()
{
mfc::test_list1();
mfc::test_list2();
return 0;
}
list.h 文件
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace mfc
{
template<class T>
//链表的链和结点分装成两个类
struct list_node //struct定义结点就直接是公有的,如果用class就要将其设为public
{
list_node<T>* _next;
list_node<T>* _prev;
T _val;
list_node(const T& val = T())
:_next(nullptr)
,_prev(nullptr)
,_val(val)
{}
};
template<class T,class Ref,class Ptr>
//迭代器的本质是通过自定义类型的封装,改变了类型的行为
//内置类型的行为不符合我们的要求时,C++就可以用一个类来封装这个类型,然后自己定义这个类型的行为
//这里的思路是,我们本身就想用结点的指针来做list的迭代器,但是因为list的结构原因
//它的++ / -- / * / != 等操作得到的结果不是我们想要的
//所以我们就把这个结点指针封装起来,重新定义它的++ / -- / * / != 等操作
//使这些操作得到的结果是我们想要的
struct __list_iterator
{
typedef list_node<T> Node;
typedef __list_iterator<T, Ref, Ptr> self;
Node* _node;
__list_iterator(Node* node)
:_node(node)
{}
//const迭代器的设计
Ref operator*()
{
return _node->_val;
}
Ptr operator->()
{
return &_node->_val;
}
//++前置
self& operator++()
{
//更新一下*this的_node指针,然后再返回*this
_node = _node->_next;
return *this;
}
//后置++
self operator++(int)
{
self tmp(*this);
//更新一下*this的_node指针,然后再返回*this
_node = _node->_next;
return tmp;
}
//--前置
self& operator--()
{
//更新一下*this的_node指针,然后再返回*this
_node = _node->_prev;
return *this;
}
//后置--
self operator--(int)
{
self tmp(*this);
//更新一下*this的_node指针,然后再返回*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>
class list
{
typedef list_node<T> Node;
public:
//因为iterator和const_iterator只有operator*和operator->的返回值不同
//所以我们不如把operator*和operator->的返回值也设置成模板参数,
//当是iterator的时候,返回值模板就是T&/T*
//当是const_iterator的时候,返回值模板就是const T&/const T*
//本质上iterator和const_iterator还是两个类,但是用模板可以简化一些
typedef __list_iterator<T,T&,T*> iterator;
typedef __list_iterator<T,const T&,const T*> const_iterator;
iterator begin()
{
//因为迭代器的底层实现是Node*,所以这里直接返回Node*没问题
//单参数的构造函数支持隐式类型转换
//return _head->_next;
//所以上下两种方式都可以
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();
}
list(const list<T>& lt)
{
empty_init();
for (auto& e : lt)
{
push_back(e);
}
}
void swap(list<T>& lt)
{
std::swap(_head, lt._head);
}
list<T>& operator=(list<T> lt)
{
swap(lt);
return *this;
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
void push_front(const T& x)
{
insert(begin(), x);
}
void pop_front()
{
erase(begin());
}
void push_back(const T& x)
{
/*
//找尾
Node* tail = _head->_prev;
Node* newnode = new Node(x);
//链接
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;
*/
insert(end(), x);
}
void pop_back()
{
erase(--end());
}
//pos位置之前插入
iterator insert(iterator pos, const T& x)
{
//纪录下pos位置和pos的上一个位置
Node* cur = pos._node;
Node* prev = cur->_prev;
//创建新结点
Node* newnode = new Node(x);
//将pos的上一个结点和新结点相互链接
prev->_next = newnode;
newnode->_prev = prev;
//将新结点和pos结点相互链接
cur->_prev = newnode;
newnode->_next = cur;
//返回新插入的结点的迭代器
return newnode;
}
//删除pos位置的结点
iterator erase(iterator pos)
{
//不能删哨兵位的头结点
assert(pos != end());
//纪录下pos位置, pos的上一个位置和下一个位置
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
//将pos的上一个位置和下一个位置相互链接
prev->_next = next;
next->_prev = prev;
//删除pos位置结点
delete cur;
//返回pos位置的下一个结点的迭代器
return next;
}
//size求法1:写函数
//方法2:加一个成员变量_size.然后insert就++,erase就--,初始化记得附0
size_t size()
{
size_t sz = 0;
iterator it = begin();
while (it != end())
{
++sz;
++it;
}
return sz;
}
private:
//写成list_node* _head;是错误的
//因为有了类模板后,类名就不是类型了,只有类模板显示实例化出的类才是类型
Node* _head;
};
//迭代器测试打印函数
void Print(const list<int>& lt)
{
list<int>::const_iterator it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
//测试函数1
void test_list1()
{
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();//这个地方把begin()赋给it是拷贝构造
//而iterator没有实现拷贝构造,则默认就是浅拷贝
//没有出错的原因就是,这里本身就是应该浅拷贝
//我把begin()赋值给it,本身就是希望it指向这个结点,而不是指向这个结点的拷贝
//那么,多个指针指向一个结点没有崩溃的原因是,我们没有进行二次释放操作
//一般来讲,指针的销毁都伴随着空间的销毁,但是迭代器并没有销毁链表结点的权力
//所以我们不写迭代器的析构函数,迭代器的销毁不导致结点的释放,所以不会有二次释放的问题
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
Print(lt);
}
//测试函数2
void test_list2()
{
class Point {
public:
int x;
int y;
Point(int xCoord = 0, int yCoord = 0)
: x(xCoord)
, y(yCoord)
{}
};
list<Point> lt;
lt.push_back(Point(1, 1));
lt.push_back(Point(2, 2));
lt.push_back(Point(3, 3));
lt.push_back(Point(4, 4));
list<Point>::iterator it = lt.begin();
while (it != lt.end())
{
cout << it->x << "," << it->y << endl;
cout << (*it).x << "," << (*it).y << endl;
cout << endl;
++it;
}
}
}
结语
希望这篇list的实现详解能对大家有所帮助,欢迎大佬们留言或私信与我交流.
学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!