既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
{
_node = _node->_prev;
return \*this;
}
前置减减和前置加加类似:
Self& operator--(int)
{
Self tmp(\*this);
_node = _node->_prev;
return tmp;
}
### 4.3 解引用
这里\*it返回的是什么值?
要返回的时节点里面的data
T& operator\*()
{
return _node->_data;
}
### 4.4 `!=`和`==`
比较两个迭代器相不相等,比较的是节点的指针
bool operator!=(const Self& it)
{
return _node != it._node;
}
重载==:
bool operator==(const Self& it)
{
return _node == it._node;
}
### 4.5 begin 和 end
begin执行第一个节点,也就是head的next
iterator begin()
{
return iterator(_head->_next);
}
这里是用来匿名对象来构造迭代器:

还可以写成:
单参数的构造,支持隐私类型转换
iterator begin()
{
return _head->_next;
}

end指向的是head
iterator end()
{
return iterator(_head);
}
### 4.6 const迭代器
不能直接在原来的迭代器上面加上const,会导致普通迭代器就不能修改了。
const迭代器,需要是迭代器不能修改,还是迭代器指向的内容?
迭代器指向的内容不能修改!const iterator不是我们需要const迭代器,所以不能在普通迭代器的前面加const。
使用就增加一个重载的const迭代器:
const_iterator begin() const
{
return _head->_next;
}
const_iterator end() const
{
return _head;
那么就得单独搞一个类ListConstIterator,让const迭代器\*it不能修改:再把相同的操作符重载一下
template
struct ListConstIterator
{
typedef ListNode Node;
typedef ListConstIterator Self;
Node\* _node;
ListConstIterator(Node\* node)
:\_node(node)
{}
// \*it
const T& operator\*()
{
return _node->_data;
}
// it->
const T\* operator->()
{
return &_node->_data;
}
// ++it
Self& operator++()
{
_node = _node->_next;
return \*this;
}
Self operator++(int)
{
Self tmp(\*this);
_node = _node->_next;
return tmp;
}
Self& operator--()
{
_node = _node->_prev;
return \*this;
}
Self operator--(int)
{
Self tmp(\*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
bool operator==(const Self& it)
{
return _node == it._node;
}
};
### 4.7 迭代器优化
发现普通迭代器和const迭代器里面很多运算符都是一样的,而const迭代器里面就直是不能修改指向的内容,代码显得冗余。就可以用模板来修改这两个类,把他们两个融成一个类。
就是返回值的类型不同,就用模板变,用一个模板参数:`template<class T, class Ref, class Ptr>`:
template<class T, class Ref, class Ptr>
struct ListIterator
{
typedef ListNode<T> Node;
typedef ListIterator<T, Ref, Ptr> Self;
Node\* _node;
ListIterator(Node\* node)
:\_node(node)
{}
// \*it
//T& operator\*()
Ref operator\*()
{
return _node->_data;
}
// it->
//T\* operator->()
Ptr operator->()
{
return &_node->_data;
}
// ++it
Self& operator++()
{
_node = _node->_next;
return \*this;
}
Self operator++(int)
{
Self tmp(\*this);
_node = _node->_next;
return tmp;
}
Self& operator--()
{
_node = _node->_prev;
return \*this;
}
Self operator--(int)
{
Self tmp(\*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
bool operator==(const Self& it)
{
return _node == it._node;
}
};
**本质上相当于我们写了一个类模板,编译器实例化生成两个类。**
从而在list类里面就修改为:
typedef ListIterator<T, T&, T\*> iterator;
typedef ListIterator<T, const T&, const T\*> const_iterator;
## 5. Modifiers
### 5.1 insert
insert实现在某一个位置之前插入一个节点
先搞一个节点,然后记录原链表pos位置的指针,然后一前一后改指向

void insert(iterator pos, const T& x)
{
Node\* cur = pos._node;
Node\* newnode = new Node(x);
Node\* prev = cur->_prev;
prev->_next = cur;
newnode->_prev = prev;
newnode->_next = cur;
cur->prev = newnode;
}
### 5.2 push\_back
新开一个节点,然后让原链表的tail指向新节点,让新节点的prev指向tail,再把head的prev改为新节点,新节点的next改为head。

代码实现:
void push\_back(const T& x)
{
Node\* newnode = new Node(x);
Node\* tail = _head->_prev;
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;
}
来测试一下:
void test_list1()
{
list 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())
{
cout << \*it << " ";
it++;
}
cout << endl;
}


push\_back用erase来实现会更简单:在end位置插入一个数
void push\_back(const T& x)
{
insert(end(), x);
}
### 5.3 push\_front
头插就是在begin插入一个数:
void push\_front(const T& x)
{
insert(begin(), x);
}
测试一下:

### 5.4 erase
先记录下要删除的节点,和它前一个节点prev 还有它的后一个节点next。然后让prev的\_next 指向next;next的\_prev 指向 prev。
删除会导致迭代器失效的问题,为了避免,就返回删除节点的下一个位置。
iterator erase(iterator pos)
{
Node\* cur = pos._node;
Node\* prev = cur->_prev;
Node\* next = cur->_next;
prev->_next = next;
next->_prev = prev;
delete cur;
return iterator(next);
}
### 5.5 pop\_back
尾删复用erase,而尾是在end前面的一个位置,所以先减减end再删除
void pop\_back()
{
erase(--end());
}

### 5.6 pop\_front
因为begin所在的位置就是头节点,所以直接删除begin就可以:
void pop\_front()
{
erase(begin());
}

### 5.7 重载operator->
用户自定义一个类型:
struct A
{
int _a1;
int _a2;
A(int a1 = 0, int a2 = 0)
:\_a1(a1)
, \_a2(a2)
{}
};
调用push\_back插入数据,可以是匿名对象,也可以多参数进行隐式类型转换:
list<A> lt;
A aa1(1, 1);
A aa2 = { 1, 1 };
lt.push\_back(aa1);
lt.push\_back(aa2);
lt.push\_back(A(2, 2));
lt.push\_back({ 3, 3 });
lt.push\_back({ 4, 4 });
但是要把数据输出到屏幕上,使用\*it是不可以的:

A是一个自定义类型,A不支持流插入,要想指出就得自己写一个重载一个。如果不想写,可以换个方式,这里的数据是公有的可以直接访问。
就直接\*it返回的是A,再拿到a1和a2的数据就可以:
list<A>::iterator it = lt.begin();
while (it != lt.end())
{
cout <<(\*it)._a1<<":" << (\*it)._a2 <<endl;
++it;
}
cout << endl;


这里A\*的一个指针访问数据是先解引用,返回A对象,再来.对象里面的成员变量:
A\* ptr = &aa1;
(\*ptr)._a1;
**迭代器就是想要模仿A\*的行为,所以迭代器就重载了一个->:it->,它返回的是data的地址。**
T\* operator->()
{
return &_node->_data;
}
访问它里面的就是这样:
cout << it->_a1 << “:” << it->_a2 << endl;
其实是编译器为了可读性,省略了一个箭头:第一个箭头是运算符重载,就返回data里面的地址也就是A\*,第二个箭头就能访问A里面的数据了。

原生指针的行为就是:
cout << it.operator->()->_a1 << “:” << it.operator->()->_a2 << endl;
测试一下都能使用:
void test\_list2()
{
list<A> lt;
A aa1(1, 1);
A aa2 = { 1, 1 };
lt.push\_back(aa1);
lt.push\_back(aa2);
lt.push\_back(A(2, 2));
lt.push\_back({ 3, 3 });
lt.push\_back({ 4, 4 });
list<A>::iterator it = lt.begin();
while (it != lt.end())
{
cout << it->_a1 << ":" << it->_a2 << endl;
cout << it.operator->()->_a1 << ":" << it.operator->()->_a2 << endl;
++it;
}
cout << endl;
}

### 5.8 swap
直接调用库里面的swap来交换:
void swap(list<T>& lt)
{
std::swap(_head, lt._head);
std::swap(_size, lt._size);
}
### 5.9 clear
clear清理掉所有数据,直接复用迭代器来把数据全部删除,但是没有清理掉哨兵位head
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
## 6. 附代码
#pragma once
#include
using namespace std;
#include<assert.h>
namespace bit
{
template
struct ListNode
{
ListNode* _next;
ListNode* _prev;
T _data;
ListNode(const T& x = T())
:\_next(nullptr)
, \_prev(nullptr)
, \_data(x)
{}
};
// typedef ListIterator<T, T&, T\*> iterator;
// typedef ListIterator<T, const T&, const T\*> const\_iterator;
template<class T, class Ref, class Ptr>
struct ListIterator
{
typedef ListNode<T> Node;
typedef ListIterator<T, Ref, Ptr> Self;
Node\* _node;
ListIterator(Node\* node)
:\_node(node)
{}
// \*it
//T& operator\*()
Ref operator\*()
{
return _node->_data;
}
// it->
//T\* operator->()
Ptr operator->()
{
return &_node->_data;
}
// ++it
Self& operator++()
{
_node = _node->_next;
return \*this;
}
Self operator++(int)
{
Self tmp(\*this);
_node = _node->_next;
return tmp;
}
Self& operator--()
{
_node = _node->_prev;
return \*this;
}
Self operator--(int)
{
Self tmp(\*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
bool operator==(const Self& it)
{
return _node == it._node;
}
};
//template<class T>
//struct ListConstIterator
//{
// typedef ListNode<T> Node;
// typedef ListConstIterator<T> Self;
// Node\* \_node;
// ListConstIterator(Node\* node)
// :\_node(node)
// {}
// // \*it
// const T& operator\*()
// {
// return \_node->\_data;
// }
// // it->
// const T\* operator->()
// {
// return &\_node->\_data;
// }
// // ++it
// Self& operator++()
// {
// \_node = \_node->\_next;
// return \*this;
// }
// Self operator++(int)
// {
// Self tmp(\*this);
// \_node = \_node->\_next;
// return tmp;
// }
// Self& operator--()
// {
// \_node = \_node->\_prev;
// return \*this;
// }
// Self operator--(int)
// {
// Self tmp(\*this);
// \_node = \_node->\_prev;
// return tmp;
// }
// bool operator!=(const Self& it)
// {
// return \_node != it.\_node;
// }
// bool operator==(const Self& it)
// {
// return _node == it._node;
// }
//};
template<class T>
class list
{
typedef ListNode<T> Node;
public:
//typedef ListIterator<T> iterator;
//typedef ListConstIterator<T> const\_iterator;
typedef ListIterator<T, T&, T\*> iterator;
typedef ListIterator<T, const T&, const T\*> const_iterator;
//iterator begin()
//{
// //return iterator(\_head->\_next);
// iterator it(\_head->\_next);
// return it;
//}
iterator begin()
{
return _head->_next;
}
iterator end()
{
return _head;
}
const_iterator begin() const
{
return _head->_next;
}
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
ListNode Node;
public:
//typedef ListIterator iterator;
//typedef ListConstIterator const_iterator;
typedef ListIterator<T, T&, T\*> iterator;
typedef ListIterator<T, const T&, const T\*> const_iterator;
//iterator begin()
//{
// //return iterator(\_head->\_next);
// iterator it(\_head->\_next);
// return it;
//}
iterator begin()
{
return _head->_next;
}
iterator end()
{
return _head;
}
const_iterator begin() const
{
return _head->_next;
}
[外链图片转存中…(img-Um0hdFL5-1715664258687)]
[外链图片转存中…(img-XDcmqGQ6-1715664258687)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新