既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
复用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;
};
![img](https://img-blog.csdnimg.cn/img_convert/f4b3fb97ef8bf8ed308edc171c9fd961.png)
![img](https://img-blog.csdnimg.cn/img_convert/77cd14960cb2891520113deaa8d97894.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**
= 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;
};
[外链图片转存中...(img-2lPAWWlE-1715755647097)]
[外链图片转存中...(img-nXqNdoqh-1715755647098)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**