补充:
适配器不仅是对容器进行了包装,而且有的会进行深加工,如优先级队列,对数据进行了调整。
一、优先级队列
声明存放在stl的queue头文件中。
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> > class priority_queue;
1.第二个模板参数的缺省参数是vector<T>,因为排序对于vector更快;
2.第三个模板参数是仿函数,用来控制优先级,然后输出;
3.优先级队列的底层是二叉树的堆,默认是大堆,可以使用仿函数实现小堆;
4.升序建大堆,降序建小堆,如降序,先建前k个为小堆,然后遍历剩下的元素往小堆里替换,最后一个元素就是第k个最大值;
5.有n个元素向上调整的时间复杂度就是O(lgn),向下调整就是O(lgn),向下调整建堆是O(n),但是有个前提就是左右子树是大堆或者小堆;
二、优先级队列的简单使用
1.常用接口
2.构造函数
与栈和队列不同的是除了默认构造外,还有一个迭代器区间构造。
template <class InputIterator>
priority_queue (InputIterator first, InputIterator last,
const Compare& comp = Compare(),
const Container& ctnr = Container());
3.简单使用
void test_priority_queue()
{
priority_queue<int, vector<int>, greater<int>> pq;
pq.push(1);
pq.push(2);
pq.push(3);
pq.push(4);
pq.push(5);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
}
int main()
{
test_priority_queue();
return 0;
}
三、模拟实现优先级队列
namespace Priority_queue
{
template <class T, class Container = std::vector<T>>
class priority_queue
{
void adjustDown(int parent) // 最后一个叶节点的父节点
{
// 找左右孩子较大的
int child = parent * 2 + 1; // 默认左孩子大,使用仿函数则将比较顺序改为左孩子 比较 右孩子
while (child < con_.size())
{
if (child + 1 < con_.size() && con_[child + 1] > con_[child])
{
child++;
}
if (con_[child] > con_[parent])
{
std::swap(con_[child], con_[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void adjustUp(int child)
{
int parent = (child - 1) / 2;
while (parent >= 0)
{
if (con_[child] > con_[parent])
{
std::swap(con_[child], con_[parent]);
child = parent;
parent = (parent - 1) / 2;
}
else
{
break;
}
}
}
public:
// 默认成员函数
// 无参构造
priority_queue() {}
// 带区间的构造函数
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
while (first != last)
{
con_.push_back(*first);
++first;
}
// 向下调整建堆
for (int i = (con_.size() - 1 - 1) / 2; i >= 0; i--) // 下标
{
adjustDown(i);
}
}
// 普通成员函数
void pop()
{
std::swap(con_[0], con_[con_.size() - 1]);
con_.pop_back();
adjustDown(0);
}
void push(const T &val)
{
// 先尾部插入一个数据,在进行向上调整
con_.push_back(val);
adjustUp(con_.size() - 1);
}
const T &top()
{
return con_[0];
}
size_t size()
{
return con_.size();
}
bool empty()
{
return con_.empty();
}
private:
Container con_;
};
}
四、仿函数
1.由于c语言的函数指针使用起来十分繁琐,所以想用仿函数来代替函数指针使用;
2.想要将函数内部哪部分的比较方式,通过外界进行修改,就将哪部分用仿函数实现;
1.什么是仿函数
1.仿函数又叫做函数对象,其中仿函数更多的指的是类,函数对象指的是实例化出来的对象;
2.仿函数实际上就是用一个类封装了一些运算符重载,使得函数对象可以像函数一样去使用;
3.以前的泛型编程是类和函数针对数据的泛型,而仿函数实现了,对比较方式的泛型编程;
2.仿函数的使用
template<class T>
class less
{
public:
bool operator(){}
};
3.仿函数特性
1.仿函数没有成员对象,仅仅是为了使用函数;
4.必须实现仿函数的场景
1.比如传入的参数是指针,但是想要比较的是指针指向的内容,如日期类指针比较大小想比较指针的内容,可是已经重载过比较了。指针类型是内置类型,而内置类型的运算符在类外是不可以改变原来效果,所以需要用仿函数来修改,operator(),可以传递多个参数,而且不会和类内定义的冲突。
五、反向迭代器
库里面使用了适配器模式来实现反向迭代器,而不是在正向迭代器的基础上对++和–做修改,做很多的重复工作。
反向迭代器定义在了iterator.h里面,是一个用正向迭代器适配的类模板,适用于所有容器;
template <class Iterator>
class reverse_iterator
{
protected:
Iterator current;
public:
typedef typename iterator_traits<Iterator>::iterator_category
iterator_category;
typedef typename iterator_traits<Iterator>::value_type
value_type;
typedef typename iterator_traits<Iterator>::difference_type
difference_type;
typedef typename iterator_traits<Iterator>::pointer
pointer;
typedef typename iterator_traits<Iterator>::reference
reference;
typedef Iterator iterator_type;
typedef reverse_iterator<Iterator> self;
public:
reference operator*() const {
Iterator tmp = current;
return *--tmp;
}
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
self& operator++() {
--current;
return *this;
}
self operator++(int) {
self tmp = *this;
--current;
return tmp;
}
self& operator--() {
++current;
return *this;
}
self operator--(int) {
self tmp = *this;
++current;
return tmp;
}
self operator+(difference_type n) const {
return self(current - n);
}
self& operator+=(difference_type n) {
current -= n;
return *this;
}
self operator-(difference_type n) const {
return self(current + n);
}
self& operator-=(difference_type n) {
current += n;
return *this;
}
reference operator[](difference_type n) const { return *(*this + n); }
};
template <class Iterator>
inline bool operator==(const reverse_iterator<Iterator>& x,
const reverse_iterator<Iterator>& y) {
return x.base() == y.base();
}
template <class Iterator>
inline bool operator<(const reverse_iterator<Iterator>& x,
const reverse_iterator<Iterator>& y) {
return y.base() < x.base();
}
template <class Iterator>
inline typename reverse_iterator<Iterator>::difference_type
operator-(const reverse_iterator<Iterator>& x,
const reverse_iterator<Iterator>& y) {
return y.base() - x.base();
}
template <class Iterator>
inline reverse_iterator<Iterator>
operator+(reverse_iterator<Iterator>::difference_type n,
const reverse_iterator<Iterator>& x) {
return reverse_iterator<Iterator>(x.base() - n);
}
1.总结
1.反向迭代器+就转换成了正向迭代器的-;
2.对于”*对象和对象指针->“不是调用正向迭代器的“*对象和对象指针->”,而是访问前一个位置,原因是rbegin()调用的是end(),rend()调用的是begin(),这样就实现了迭代器镜像对称。
2.模拟实现反向迭代器
1.成员函数的返回值类型实现的方式有两种,1.迭代器萃取;2.传递模板参数(更容易一些);
2.内置类型使用浅拷贝满足条件
namespace Reverse_iterator
{
template <class Iterator, class Ref, class Ptr>
class reverse_iterator
{
public:
typedef reverse_iterator<Iterator, Ref, Ptr> Self;
public:
// 默认成员函数
reverse_iterator(Iterator it) : current_(it) {}
public:
// 普通成员函数
Ref operator*()
{
Iterator tmp(current_);
return *(--tmp);
}
Ptr operator->()
{
return &operator*();
}
Self &operator++()
{
--current_;
return *this;
}
Self &operator--()
{
++current_;
return *this;
}
Self operator++(int)
{
Self tmp(current_);
current_--;
return tmp;
}
Self operator--(int)
{
Self tmp(current_);
current_++;
return tmp;
}
bool operator!=(const Self &iterator) const
{
return current_ != iterator.current_;
}
bool operator==(const Self &iterator) const
{
return current_ == iterator.current_;
}
private:
Iterator current_;
};
}