容器适配器
概念:
适配器是一种设计模式,是将一个类的接口转换成客户希望的另外一个接口。
为什么将stack queue priority_queue称为容器适配器
在STL中并没有将stack queue priority_queue划分在容器的行列,这是因为其他的每个容器在底层都有自己的实现方式,而stack、queue、priority_queue只是在底层将其他容器进行了重新封装。
stack适配器的模拟实现
stack在底层用的是双端队列deque。
namespace My_Code
{
template<class T, class Container = deque<T>>
class stack
{
public:
stack()
{}
void push(const T& data)
{
_con.push_back(data);
}
void pop()
{
_con.pop_back();
}
size_t size()const
{
return _con.size();
}
bool empty()const
{
return _con.empty();
}
T& top()
{
return _con.back();
}
const T& top()const
{
return _con.back();
}
private:
Container _con;
};
#include<vector>
int main()
{
bite::stack<int> s;
s.push(1);
s.push(2);
s.push(3);
s.push(4);
cout << s.size() << endl;
cout << s.top() << endl;
s.pop();
cout << s.size() << endl;
cout << s.top() << endl;
if (s.empty())
cout <<"yes" << endl;
else
cout << "no" << endl;
cout << "以下为s2" << endl;
bite::stack<int, vector<int>> s2;//stack的底层用vector也是可以的。
s2.push(1);
s2.push(2);
s2.push(3);
s2.push(4);
cout << s2.size() << endl;
cout << s2.top() << endl;
s2.pop();
cout << s2.size() << endl;
cout << s2.top() << endl;
if (s2.empty())
cout << "yes" << endl;
else
cout << "no" << endl;
queue适配器的模拟实现
queue在底层用的也是双端队列deque
template<class T, class Container = deque<T>>
class queue
{
public:
queue()
{}
void push(const T& data)
{
con.push_back(data);
}
void pop()
{
con.pop_front();
}
size_t size()
{
return con.size();
}
T& front()
{
return con.front();
}
const T& front()const
{
return con.front();
}
T& back()
{
return con.back();
}
const T& back()const
{
return con.back();
}
bool empty()
{
return con.empty();
}
private:
Container con;
};
#include<list>
int main()
{
bite::queue<int> q;
q.push(1);
q.push(2);
q.push(3);
q.push(4);
cout << q.size() << endl;
cout << q.front() << endl;
cout << q.back() << endl;
q.pop();
cout << q.size() << endl;
cout << q.front() << endl;
cout << q.back() << endl;
cout << "以下为q2" << endl;
bite::queue<int, list<int>> q2;//queue的底层也可以用list实现
q2.push(5);
q2.push(2);
q2.push(3);
q2.push(4);
cout << q2.size() << endl;
cout << q2.front() << endl;
cout << q2.back() << endl;
q2.pop();
cout << q2.size() << endl;
cout << q2.front() << endl;
cout << q2.back() << endl;
}
为什么要选用deque来做stack 以及queue配适器的底层默认容器。
- stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
- 在stack中元素增长时,deque比vector的效率高(vector需要扩容,效率低);queue中的元素增长时,deque不仅效率高,而且内存使用率高。
priority_queue适配器的模拟实现
priority_queue底层用的是vector。
namespace My_Code
{
template<class T,class Container=vector<T>,class compare =less<T>>
class priority_queue
{
public:
priority_queue()
:con()
{}
template<class Iterator>
priority_queue(Iterator first, Iterator last)//将输入con中的数据调整成堆,用向下排序法
: con(first,last)
{
int root = ((con.size() -2)>>1);//因为想要将数组中无序的数,变为堆,就要满足树从下往上都是堆,所以从最后一个非叶子节点开始向下调整。
//这里的((con.size() -2)>>1)代表的是通过con中最后一个数据的下标来找到其父节点。这个式子实际上是:((con.size()-1)-1)/2
for (; root >= 0; root--)//从最后一个非叶子节点开始向根节点遍历,依次进行向下排序。
{
AdjustDown(root);
}
}
void push(const T& data)//在数组后面插入一个元素,为了不破坏大堆或者小堆的结构,
//从最后一个数开始进行一遍向上排序。
{
con.push_back(data);
AdjustUp(con.size()-1);
}
void pop()//删除第一个元素。因为底层用的是vector,所以不能直接删除,应将头元素和最后一个元素交换,
//再进行数组的尾删操作,因为删除后改变了堆,所以从根节点进行向下排序。
{
if (empty())
return;
swap(con.front(), con.back());
con.pop_back();
AdjustDown(0);
}
size_t size()const
{
return con.size();
}
bool empty()const
{
return con.empty();
}
const T& top()const
{
return con.front();
}
private:
void AdjustDown(int parent)//堆的向下调整法
{
int child = (parent * 2) + 1;
while (child < size())
{
if (child + 1 < size() && com(con[child], con[child + 1]))
child += 1;
if (com(con[parent], con[child]))
{
swap(con[parent], con[child]);
parent = child;
child = (parent * 2) + 1;
}
else
break;
}
}
void AdjustUp(int child) // 堆的向上调整法
{
int parent = ((child - 1) >> 1);
while (child)
{
if (com(con[parent], con[child]))
{
swap(con[parent], con[child]);
child = parent;
parent = ((child - 1) >> 1);
}
else
return;
}
}
private:
Container con;
compare com;
};
}
void Testpriority_queue()
{
int arr[] = { 8 , 1 , 9 , 3 , 6 , 4 , 5 , 0 };
bite::priority_queue<int> Pq(arr,arr+sizeof(arr)/sizeof(arr[0]));
cout << Pq.top() << endl;
Pq.pop();
cout << Pq.top() << endl;
Pq.push(10);
cout << Pq.top() << endl;
}
用区间构造一个优先级队列————大堆。
分别完成上述三种操作的Pq.top()