适配器
🔥什么是适配器
以下是我在百度上看到的一句话。
Adapter是一种重用代码的方式,当我们实现了一个concept,但在开发过程中发现需要另外一个concept,而刚好新的concept是老的concept的子集,那么我们可以限制老的concept的功能,使它适合我们的新concept,我们称这个过程为适配(Adapt)。
对于这句话,我的理解如下。
- 利用已经存在的东西组合或者限制实现一个新的东西,这个新的东西具有某种新的性质,但是他的底层是由已经存在的东西实现的。
- 适配器是利用一种比较通用的数据结构来实现更加具体的,更加贴近实际应用的一种数据结构。
举个生活中的例子
我们平常接触到的电流是220v,但是给手机充电时,肯定是用不了这么高的电压,所以我们通过“电源适配器”的转化,(充电器的全称是“电源适配器”,)变成合适的电压才能给手机充电。这里的“充电器”就起到了适配的作用。
🔥几种常见的适配器
c++中的适配器有三种:容器适配器,迭代器适配器,函数适配器
容器适配器:具体的有stack,queue,priorty-queue,默认的情况如下:stack和queue是基于deque实现的。
priorty-queue是在vector上实现的,可以根据第二个实参指定容器的类型,但是一定要符合标准,queue要求有push_back的操作,因此不能建立在vector的基础上,priorty-queue要求有随机访问的功能,因此建立在vector上。
🔥适配器如何使用
本文主要讲解priority_queue(优先级队列),我们需要了解以下知识:
- 优先级队列的底层使用堆实现的,因为堆的效率高,所以才用堆实现。
- 适配器的模版参数有多个,他们分别是:
- template <class T, class Container = vector, class Compare = less > class priority_queue;
画张图理解一下
void test()
{
std::priority_queue<int,vector<int>,less<int>> pq;
pq.push(1);
pq.push(5);
pq.push(0);
pq.push(2);
while (!pq.empty())
{
cout << pq.top()<<" ";
pq.pop();
}
cout << endl;
}
输出的结果如下:
如图可以看出,他是按照降序排序的。
同样的代码只需要改变一点,就能实现升序
void test()
{
std::priority_queue<int,vector<int>,greater<int>> pq;
pq.push(1);
pq.push(5);
pq.push(0);
pq.push(2);
while (!pq.empty())
{
cout << pq.top()<<" ";
pq.pop();
}
cout << endl;
}
输出结果如下
🔥适配器的模拟实现(以prrority_queue为例)
🏠 向上调整算法
//向上调整算法
void AdjustUp(int child)
{
Compare com;
int parent = (child - 1) / 2;
while (child>0)//直到孩子到达堆顶结束比较
{
if(com(_con[parent],_con[child]))
//if (_con[child] > _con[parent])// 父亲小于孩子,孩子往上调
{
swap(_con[parent], _con[child]);//交换两个节点
child = parent;//更新child
parent = (child - 1) / 2;//更新parent
}
else
{
break;
}
}
}
🏠 向下调整算法
//向下调整算法
void AdjustDown(int root)
{
Compare com;
int parent = root;
int child = parent * 2 + 1;
while (child<_con.size())
{
//选出左右孩子大的哪一个
//if (child + 1 < _con.size() && _con[child+1] > _con[child ])
if(child+1<_con.size()&&com(_con[child],_con[child+1]))
{
++child;
}
if(com(_con[parent],_con[child]))
//if (_con[child] > _con[parent]) 父亲大于孩子,孩子往上调
{
swap(_con[parent], _con[child]);
parent = child;
child = parent + 2 + 1;
}
else
{
break;
}
}
}
🏠 插入数据
void push(const T& x)
{
_con.push_back(x);//插入数据之后破化了堆得性质
AdjustUp(_con.size()-1);//从最后的位置开始调,调用向上调整算法,调成大堆
}
🏠 删除数据
void pop()
{
swap(_con[0], _con[_con.size() - 1]);//交换堆顶数据和最后一个数据
_con.pop_back();//出堆顶的数据
AdjustDown(0);//从跟的位置向下调整
}
🏠 取出top数据
T& top()
{
return _con[0];
}
🏠 判空
bool empty()
{
return _con.empty();
}
🏠 元素个数(size)
size_t size()
{
return _con.size();
}