🪐🪐🪐欢迎来到程序员餐厅💫💫💫
今日主菜: priority_queue类及反向迭代器
主厨:邪王真眼
主厨的主页:Chef‘s blog
所属专栏:c++大冒险
向着c++,塔塔开!
[本节目标]
-
1.仿函数
-
2.priority_queue
-
3.反向迭代器
一.仿函数
1.1仿函数是什么
仿函数(Functor)是一种重载了函数调用运算符(operator())的类对象,他的使用方法看起来与函数极其相似,却又有不同,因此成为仿函数
1.2仿函数的定义与使用
我们现在写一个可以比较两个变量大小的仿函数以及函数
template<class T>
class Less
{
bool operator()(const T&a,const T&b )
{
return a < b;
}
};
template<class T>
bool Less(const T& a, const T& b )
{
return a < b;
}
那么问题来了,仿函数的优势是什么呢?
我们知道有时候为了在函数中调用别的函数我们需要传一个叫做函数指针的东西,简单的函数还好,复杂的函数的指针是真的难看懂,于是乎,仿函数横空出世,你要用它就传个他的类就行,一下子容易多了。
二、priority_queue
2.1 priority_queue的介绍
- empty():检测容器是否为空
- size():返回容器中有效元素个数
- front():返回容器中第一个元素的引用
- push_back():在容器尾部插入元素
- pop_back():删除容器尾部元素
2.2成员变量
template<class T, class Container = vector<T>, class Compare = Less<T>>
class priority_queue
{
public:
//函数
private:
Container _con;
};
2.3empty
bool empty()
{
reutrn _con.empty();
}
2.4size
返回容器适配器的元素个数
size_t size()
{
return _con.size();
}
2.5top
返回堆顶元素
注意事项:我们的返回值是const类型,没有非const,这是因为如果你用非const就可能导致堆顶元素修改,进而导致结构不再是大堆或小堆。
constT& top()const
{
_con.front();
}
2.6push
入堆
- 1.先尾插
- 2.在向上调整
void push(T& val)
{
_con.push_back(val);
UpAdjust();
}
void UpAdjust(size_t number)//大堆
{
int child = number - 1;
int parent = child = (child-1) / 2;
while (child)
{
if (_con[child] > _con[parent])
{
swap(_con[child], _con[parent]);
child = parent;
parent = (child-1) / 2;
}
else
break;
}
}
这里我们既要思考,如果建一个小堆那就要在写一个函数,可是他们两个函数只有
这里需要改变,一个是>,一个是<。
于是乎,我们立刻想到了再加一个模板参数,用它来处理这个大于小于的问题,
如下:
template<class T>
class Less
{
bool operator()(const T&a,const T&b )
{
return a < b;
}
};
template<class T>
class Greater
{
bool operator()(const T& a, const T& b)
{
return a > b;
}
};
void push(T& val)
{
_con.push_back(val);
UpAdjust();
}
Compare com;
void UpAdjust(size_t number)//大堆
{
int child = number - 1;
int parent = child = (child-1) / 2;
while (child)
{
if (com(_con[parent] , _con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (child-1) / 2;
}
else
break;
}
}
2.7pop
出堆
这个就比较难了,为了保证堆的结构尽可能不被破坏以降低时间复杂度,我们选择:
- 先把第一个元素和最后一个元素交换位置
- 最后删除最后一个元素。
- 在对堆顶进行向下调整法
- 构造一个仿函数模板对象,再利用重载的()运算符进行比较
template<class T>
class Less
{
bool operator()(const T&a,const T&b )
{
return a < b;
}
};
template<class T>
class Greater
{
bool operator()(const T& a, const T& b)
{
return a > b;
}
};
Compare com;
void DownAdjust(size_t size)
{
int parent = 0;
int child = parent * 2+1;
while (child<size)
{
if (child<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;
}
}
void pop()
{
swap(_con[0], _con[size() - 1]);
_con.pop_back();
DownAdjust(size());
}
三、反向迭代器
反向迭代器是一种适配器,它是根据不同容器的正向迭代器,来生成对应的反向迭代器。
反向迭代器的rbegin对应迭代器的end位置,rend对应begin位置。
3.1 成员变量
细节:
- 使用struct,标明公有属性
- 成员变量是一个正向迭代器
template <class Iterator,class Ref,class Ptr>
struct ReverseItreator
{
typedef ReverseIterator<Iterator, Ref, Ptr> self;
Iterator it;
};
3.2默认成员函数
写一个缺省的构造,别的编译器自动生即可。
ReverseItreator(Iterator val=Iterator())
:it(val)
{}
3.3operator*
Ref operator*()
{
Iterator its = it;
its--;
return *its;
}
3.4operator--
self operator--()
{
return ++it;
}
self operator--()const
{
Iterator its = it;
++it;
return its;
}
3.5operator++
self operator++()
{
return --it;
}
self operator++()const
{
Iterator its = it;
--it;
return its;
}
3.6operator->
Ptr operator->()
{
return & (*it);
}
3.7operator==,operator!=
bool operator==(const self&s)
{
return it = s.it;
}
bool operator !=(const self& s)
{
return it = s.it;
}
3.8反向迭代器的应用
在容器中,以vector举例
template<class T>
class vector
{
public:
typedef T* Iterator;
typedef const T* Const_Iterator;
typedef ReverseIterator<Iteartor, T&, T*> Reverse_Iterator;
typedef ReverseIterator<Iteartor, constT&,cosnt T*> Const_Reverse_Iterator;
Iterator end()
{
return _finish;
}
Const_Iterator end()const
{
return _finish;
}
Iterator begin()
{
return _start;
}
Const_Iterator begin()const
{
return _start;
}
private:
T* _start;
T* _finish;
};
反向迭代器函数:
Reverse_Iterator rbegin()
{
return (Reverse_Iterator)end();
}
Const_Reverse_Iterator rbegin()const
{
return (Const_Reverse_Iterator)end();
}
Reverse_Iterator rend()
{
return (Reverse_Iterator)begin();
}
Const_Reverse_Iterator rend()const
{
return (Const_Reverse_Iterator)begin();
}
这时候我们就要提个问题了,就拿rbegin了,来说吧
看看这个函数怎么样:
Reverse_Iterator begin()
{
return _finish;
}
乍一看似乎完全没问题,但是但是,如果是list你咋办呢,是deque你咋办呢,他们都没有这个
_finish成员变量啊,所以我们一开始就说了,它是根据不同容器的正向迭代器,来生成对应的反向迭代器。反向迭代器去调用正向迭代器的实现方法才能保证他的普适性。
总结
- 仿函数的用法及优势,并在priority_queue适配器中加以应用
- 对priority_queue进行了了解和模拟,
- 实现很久前就提到的了反向迭代器,对迭代器这个概念有了更深的了解。
感觉有用的话就点个赞支持一下吧