目录
-------------反向迭代器------------
[3.1 模板参数解析](#3.1 模板参数解析)
[3.2 类型别名与成员变量](#3.2 类型别名与成员变量)
[3.3 构造函数](#3.3 构造函数)
[3.4 取值运算符 operator*](#3.4 取值运算符 operator*)
[3.5 箭头运算符 operator->](#3.5 箭头运算符 operator->)
[3.6 前置 ++ 运算符 operator++](#3.6 前置 ++ 运算符 operator++)
[3.7 后置 ++ 运算符 operator++(int)](#3.7 后置 ++ 运算符 operator++(int))
[3.8 前置 -- 运算符 operator--](#3.8 前置 -- 运算符 operator--)
[3.9 后置 -- 运算符 operator--(int)](#3.9 后置 -- 运算符 operator--(int))
[3.10 不等比较运算符 operator!=](#3.10 不等比较运算符 operator!=)
-------------优先级队列------------
[3.1 类模板定义](#3.1 类模板定义)
[3.2 AdjustDown 向下调整算法](#3.2 AdjustDown 向下调整算法)
[3.3 AdjustUp 向上调整算法](#3.3 AdjustUp 向上调整算法)
[3.4 默认构造函数](#3.4 默认构造函数)
[3.5 范围构造函数](#3.5 范围构造函数)
[3.6 pop 弹出堆顶元素](#3.6 pop 弹出堆顶元素)
[3.7 push 插入新元素](#3.7 push 插入新元素)
[3.8 top 获取堆顶元素](#3.8 top 获取堆顶元素)
[3.9 empty 判断队列是否为空](#3.9 empty 判断队列是否为空)
[3.10 size 获取队列元素个数](#3.10 size 获取队列元素个数)
-------------反向迭代器------------
1、适配器模式
要实现反向迭代器,就不得不提到适配器模式
在上一篇内容中,我们学习的 stack 和 queue 就是典型的容器适配器 ;而今天要讲的反向迭代器,则是一种迭代器适配器
2、反向迭代器原理
反向迭代器是一个迭代器适配器,它包装了一个正向迭代器,把 ++ 操作映射成原迭代器的 --,把 -- 操作映射成原迭代器的 ++,从而实现反向遍历的效果
反向迭代器在容器中的指向:

3、反向迭代器的实现
cpp
namespace ljh
{
//typedef iterator<iterator, T& , T*> iterator;
//typedef iterator<iterator, const T& , const T*> iterator;
template<class Iterator, class Ref, class Ptr>
struct ReverseIterator
{
typedef ReverseIterator<Iterator, Ref, Ptr> Self;
Iterator _it;
ReverseIterator(Iterator it)
:_it(it)
{
}
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
Ptr operator->()
{
return &(operator*());
}
Self& operator++()
{
--_it;
return *this;
}
//由于没写析构函数,所以不用担心拷贝构造是浅拷贝
Self operator++(int)
{
Self tmp(*this);
--_it;//正向迭代器--,反向迭代器++
return tmp;
}
Self& operator--()
{
++_it;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
++_it;
return tmp;
}
bool operator!=(const Self& s) const
{
return _it != s._it;
}
};
typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef ReverseIterator<const_iterator, const T&, const T*const_reverse_iterator;
/*===================反向迭代器=====================*/
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
const_reverse_iterator rbegin()const
{
return reverse_iterator(end());
}
const_reverse_iterator rend() const
{
return reverse_iterator(begin());
}
}
3.1 模板参数解析
cpp
template<class Iterator, class Ref, class Ptr>
struct ReverseIterator
Iterator: 被适配的正向迭代器类型(比如 vector::iterator)
Ref:迭代器取值(*it)时返回的引用类型(比如 T& 或 const T&)
Ptr:迭代器箭头访问(it->)时返回的指针类型(比如 T* 或 const T*)
3.2 类型别名与成员变量
cpp
typedef ReverseIterator<Iterator, Ref, Ptr> Self;
Iterator _it;
Self:简化自身类型的书写,避免重复写长模板名
_it:内部持有的正向迭代器,是反向迭代器的 "核心数据"
3.3 构造函数
cpp
ReverseIterator(Iterator it) : _it(it) {}
用一个正向迭代器来初始化反向迭代器,把传入的迭代器保存到 _it 中。
3.4 取值运算符 operator*
cpp
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
这是反向迭代器的核心适配逻辑。
它先拷贝一份内部迭代器 _it,对拷贝做 -- 移动到前一个位置,再取值返回。
这样保证了 rbegin() 能正确指向容器的最后一个元素。
3.5 箭头运算符 operator->
cpp
Ptr operator->()
{
return &(operator*());
}
复用 operator* 的结果,取其地址返回,支持 it->member 这样的指针访问语法。
3.6 前置 ++ 运算符 operator++
cpp
Self& operator++()
{
--_it;
return *this;
}
反向迭代器的 ++ 对应内部正向迭代器的 --,实现 "向后移动"(在反向遍历中是向前走)。
3.7 后置 ++ 运算符 operator++(int)
cpp
Self operator++(int)
{
Self tmp(*this);
--_it;
return tmp;
}
先创建一个当前对象的副本,再移动内部迭代器,最后返回副本。
这是后置 ++ 的标准实现,保证返回的是 "移动前" 的迭代器。
3.8 前置 -- 运算符 operator--
cpp
Self& operator--()
{
++_it;
return *this;
}
反向迭代器的 -- 对应内部正向迭代器的 ++,实现 "向前移动"(在反向遍历中是向后退)。
3.9 后置 -- 运算符 operator--(int)
cpp
Self operator--(int)
{
Self tmp(*this);
++_it;
return tmp;
}
逻辑同后置 ++,先拷贝再移动,返回移动前的迭代器。
3.10 不等比较运算符 operator!=
cpp
bool operator!=(const Self& s) const
{
return _it != s._it;
}
bool operator==(const Self& s) const
{
return _it == s._it;
}
直接比较两个反向迭代器内部持有的正向迭代器,判断它们是否指向不同位置。
cpp
// 先定义反向迭代器的类型别名(依赖之前的 ReverseIterator 适配器)
typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;
// 1. 普通版 rbegin():可读写反向迭代器起点
reverse_iterator rbegin()
{
// 核心:用正向迭代器的 end() 初始化反向迭代器,指向容器最后一个元素
return reverse_iterator(end());
}
// 2. 普通版 rend():可读写反向迭代器终点
reverse_iterator rend()
{
// 核心:用正向迭代器的 begin() 初始化反向迭代器,指向第一个元素之前
return reverse_iterator(begin());
}
// 3. const版 rbegin() const:只读反向迭代器起点
const_reverse_iterator rbegin() const
{
// 核心:逻辑同普通版,但返回 const 版本,仅支持读操作
return const_reverse_iterator(end());
}
// 4. const版 rend() const:只读反向迭代器终点
const_reverse_iterator rend() const
{
// 核心:逻辑同普通版,但返回 const 版本,仅支持读操作
return const_reverse_iterator(begin());
}

-------------优先级队列------------
1、仿函数
仿函数(Functor)是 C++ 中一种特殊的类对象,核心特点是重载(重载)了 operator() 运算符,使得对象可以像函数一样被调用(用 对象名(参数) 的形式)。
简单说:仿函数是 "像函数的对象",本质是带 operator() 的类实例。
cpp
template<class T>
class small
{
public:
bool operator()(const T& x,const T& y)
{
return x < y;
}
};
template<class T>
class big
{
public:
bool operator()(const T& x,const T& y)
{
return x > y;
}
};
int main()
{
small<int> s;
big<int> b;
cout << s(1,2) << endl;
cout << b(1, 2) << endl;
return 0;
}

对初次接触的读者来说,仿函数的调用方式(比如 s(1,2))确实显得有些陌生,和我们熟悉的 +、= 等运算符重载的写法很不一样。你可能暂时会疑惑它的实际价值,这很正常 ------ 当我们后续用它来定制优先级队列的比较规则时,这种设计的灵活性和必要性就会清晰地展现出来。
2、优先级队列介绍
priority_queue 是 C++ 标准库中的一个容器适配器 ,底层默认用 vector 存储数据,内部维护一个堆结构,确保队首元素始终是优先级最高的(默认是最大值)。
核心特点:
只能访问队首的最大元素,不能遍历或随机访问其他元素。
插入新元素时,会自动调整堆结构以维持优先级顺序。
弹出队首元素后,剩余元素也会自动重新调整。
底层原理 :通过调用 make_heap、push_heap、pop_heap 等算法函数来维护堆的特性。
默认行为 :默认是大顶堆(最大元素优先),可以通过传入仿函数(如 greater<T>)改为小顶堆。
3、优先级队列的实现
cpp
namespace ljh
{
// 仿函数/函数对象
template<class T>
class Less
{
public:
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template<class T>
class Greater
{
public:
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
template<class T,class Container = vector<T> , class Compare = Less<T> >
class priority_queue
{
private:
//默认建大堆
void AdjustDown(int parent)
{
Compare com;//仿函数对象
int child = parent * 2 + 1;
while (child < _con.size())
{
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
//if (child + 1 < _con.size() && _con[child] < _con[child + 1])
{
++child;
}
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
//向上调整算法
void AdjustUp(int child)
{
Compare com;//仿函数对象
int parent = (child - 1)/2;
while (child > 0)
{
if (com(_con[parent],_con[child]))
{
swap(_con[parent],_con[child]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
public:
//默认构造
priority_queue()
{
}
//范围构造
template<class InputIterator>
priority_queue(InputIterator first,InputIterator last)
{
while (first!=last)
{
_con.push_back(*first);
first++;
}
//建堆-向下调整建堆(默认建立大堆)
//N
for (int i = (_con.size() - 2) / 2; i >= 0; i--)
{
//向下调整算法
AdjustDown(i);
}
}
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
void push(const T& x)
{
_con.push_back(x);
AdjustUp(_con.size() - 1);
}
const T& top()
{
return _con[0];
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
private:
Container _con;
};
}
3.1 类模板定义
cpp
template<class T, class Container = vector<T>, class Compare = Less<T>>
class priority_queue
这是整个优先级队列的模板定义,有三个模板参数:
**T:**队列中存储的元素类型。
**Container:**底层存储数据的容器,默认用 vector,也可以换成 deque 等支持随机访问的容器。
**Compare:**比较规则的仿函数,默认是 Less<T>(大顶堆),可以换成 Greater<T> 实现小顶堆。
3.2 AdjustDown 向下调整算法
cpp
void AdjustDown(int parent)
{
Compare com;
int child = parent * 2 + 1;
while (child < _con.size())
{
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
++child;
}
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
这是维护堆结构的核心函数,用来在堆顶元素被移除后,把新的堆顶向下调整到正确位置:
先创建一个比较规则的仿函数对象 con。
从 parent 的左孩子 child = parent*2+1 开始。
先在左右孩子中,用 com 比较出优先级更高的那个,作为真正要交换的 child。
然后用 com 比较父节点和这个孩子节点,如果父节点优先级更低,就交换它们,并继续向下调整。
如果父节点优先级已经更高,说明调整完成,直接跳出循环。
3.3 AdjustUp 向上调整算法
cpp
void AdjustUp(int child)
{
Compare com;
int parent = (child - 1) / 2;
while (child > 0)
{
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
这个函数用来在新元素插入堆尾后,把它向上调整到正确位置:
创建比较规则的仿函数对象 con。
计算当前 child 节点的父节点 parent = (child-1)/2。
用 con 比较父节点和孩子节点,如果父节点优先级更低,就交换它们,并继续向上调整。
如果父节点优先级已经更高,说明调整完成,跳出循环。
3.4 默认构造函数
cpp
priority_queue()
{}
空的默认构造函数,底层容器 _con 会自己调用默认构造,不需要额外操作。
3.5 范围构造函数
cpp
template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
while (first != last)
{
_con.push_back(*first);
first++;
}
for (int i = (_con.size() - 2) / 2; i >= 0; i--)
{
AdjustDown(i);
}
}
这个构造函数可以用一段迭代器区间来初始化队列:
先把区间里的所有元素都插入到底层容器 _con 中。
然后从最后一个非叶子节点开始,依次调用 AdjustDown,把整个容器调整成一个合法的堆结构。
3.6 pop 弹出堆顶元素
cpp
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
弹出堆顶元素的步骤:
先把堆顶元素(_con[0])和堆尾元素交换。
然后删除堆尾元素(也就是原来的堆顶)。
最后对新的堆顶元素调用 AdjustDown,重新维护堆的结构。
3.7 push 插入新元素
cpp
void push(const T& x)
{
_con.push_back(x);
AdjustUp(_con.size() - 1);
}
插入新元素的步骤:
先把新元素插入到底层容器的尾部。
然后对这个新插入的元素调用 AdjustUp,把它向上调整到正确的位置,以维持堆的性质。
3.8 top 获取堆顶元素
cpp
const T& top()
{
return _con[0];
}
直接返回底层容器的第一个元素,也就是堆顶元素。因为堆顶始终是优先级最高的元素。
3.9 empty 判断队列是否为空
cpp
bool empty()
{
return _con.empty();
}
直接调用底层容器的 empty() 方法,判断队列是否为空。
3.10 size 获取队列元素个数
cpp
size_t size()
{
return _con.size();
}
直接返回底层容器的大小,也就是队列中元素的个数。
