一:什么是容器适配器;
二:通过适配器模式来实现stack(栈),queue(队列);
三:STL库中的容器适配器(deque);
四:优先级队列(priority_queue);
五:仿函数(比较);
//////
一:什么是容器适配器:
//////
二:通过适配器模式来实现stack(栈),queue(队列):
如上述所言,栈分两种(数组栈与链式栈),那么我们如何来实现呢?
具体代码如下所示:
//通过vector/list实现栈:
namespace MKL
{
//通过适配器模式实现,模板给个容器名称,容器名称可以任意,给缺省值,缺省值是容器,在此默认实现数组形式的栈:
template<class T,class container=vector<T>>
class stack
{
public:
void push(const T& x)//进栈:
{
_st.push_back(x);//调用模板中的容器的尾插接口,
}
void pop()//出栈:
{
_st.pop_back();//调用模板中的容器的尾删接口,
}
const T& top()//获取栈顶元素:
{
return _st.back();//调用模板中的容器的尾获取尾部元素接口,
}
size_t size()//栈中元素个数;
{
return _st.size();//调用模板中的容器的获取元素个数接口;
}
bool empty()//判断栈是否为空:
{
return _st.empty();//调用模板中的容器的是否为空接口;
}
private:
//通过模板中的容器来定义一个栈,此时,实现的是数组栈,所以是通过缺省值vector来定义的
//但是当模板中的容器发生改变时,调用不同的容器来定义,这个栈的性质就发生了根本变化;
container _st;
};
void test_stack1()
{
//数组栈:
//stack<int> st;//因为有缺省值vector,不写也不会报错,正常运行;
//stack<int, vector<int>> st;//也可以显示的写成所使用的容器;
//链式栈:
//只需要改变模板中的容器,那么栈的性质将发生改变改变;
stack<int, list<int>> st;//此时模板中的容器是list,所以实现的是链式栈;
st.push(1);
st.push(2);
st.push(3);
st.push(4);
st.push(5);
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
cout << endl;
}
}
为便于理解,调试观察,如下图所示:
//
由于队列需要队尾入,队头出,涉及头插头删,此时就不适合使用数组(vector)来实现,队列我们优先使用list来实现,具体代码如下所示:
//通过list实现队列
namespace MKL
{
template<class T,class container=list<T>>
class queue
{
public:
void push(const T& x)//进队列:
{
_qu.push_back(x);//调用模板中的容器的尾插接口,
}
void pop()//出队列
{
_qu.pop_front();调用模板中的容器的头删接口,
}
const T& top()//获取队头元素:
{
return _qu.front();//调用模板中的容器的获取头部元素接口,
}
const T& back()//获取队尾元素
{
return _qu.back();//调用模板中的容器的获取尾部元素接口,
}
bool empty()//判断队列是否为空:
{
return _qu.empty();//调用模板中的容器的是否为空接口;
}
private:
container _qu;//主要用容器list定义,
};
void test_queue1()
{
//因为队列需要队头出数据,所以vector就不适应于实现queue,
//实现queue主要靠list,list头插头删,任意地方插入删除效率高;
queue<int, list<int>> qu;
qu.push(1);
qu.push(2);
qu.push(3);
qu.push(4);
qu.push(5);
while (!qu.empty())
{
cout << qu.top() << " ";
qu.pop();
}
cout << endl;
}
}
//////
三:STL库中的容器适配器(deque):
![](https://img-blog.csdnimg.cn/b1359731ac474857ad1fb1b074aab5d4.png)
那么什么是deque, deque又是怎样实现的呢?他存在的意义又是是什么呢?
//
3.1deque定义:
众所周知
vector: 1:优点:尾插尾删效率高,支持下标访问
2:缺点:头插头删效率低,需要挪动,
list: 1:优点:任意地方插入删除效率高,不需要挪动数据
2:缺点:不支持下标的随机访问
我们如果即想拥有vector与list的优点,又想克服他们的缺点,那么此时,deque随之孕育而生,
deque就像vector与list的结合体,
定义:deque(双端队列):是一种双开口的"连续"空间的数据结构,
![](https://img-blog.csdnimg.cn/93df053841ac4da7a2b85252e88a717c.png)
//
![](https://img-blog.csdnimg.cn/748c04f9eb2e48ac94fd9bcccdb4e963.png)
双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此,deque的迭代器会有点复杂,如下图所示:
//
3.3deque的缺陷:
四:优先级队列(priority_queue)
4.1:文档定义:
template<class T, class container = vector<T>>
class priority_queue
{
public:
//向上调整建大堆:
void adjust_up(int child)
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
if (_pq[child] > _pq[parent])
{
swap(_pq[child], _pq[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void push(const T& x)//插入:
{
_pq.push_back(x);
adjust_up(_pq.size() - 1);
}
//向下调整保持堆形:
void adjust_down(int parent)
{
size_t child = parent * 2 + 1;
while (child < _pq.size())
{
if (child + 1 < _pq.size() && (_pq[child] < _pq[child + 1]))
{
++child;
}
if (_pq[parent]<_pq[child])
{
swap(_pq[child], _pq[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void pop()//删除:
{
swap(_pq[0], _pq[_pq.size() - 1]);
_pq.pop_back();
adjust_down(0);
}
const T& top()//获取堆顶元素
{
return _pq[0];
}
size_t size()//堆内元素个数
{
return _pq.size();
}
bool empty()//判空:
{
return _pq.empty();
}
private:
container _pq;
};
void test_priority_queue()
{
priority_queue<int, vector<int>> pq;//默认排的降序,
pq.push(1);
pq.push(12);
pq.push(3);
pq.push(10);
pq.push(21);
pq.push(5);
pq.push(9);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
}
由程序知,priority_queue默认是大堆,排降序,那么如何能排升序呢?大概有两种方法:
1:改变堆的形状,建小堆,这样默认排序时就是升序;
2:通过重载"()",引入仿函数,;
第一种情况我们需要改变类中的结构,破坏了封装,所以我们舍弃,我们主要利用重载“()”,利用仿函数(比较)来实现排序自由,由我们自己决定排序的方式!
五:仿函数(比较)
仿函数,也叫做函数对象。
就其意义而言:“函数对象”较为合适,一种具有函数特性的对象,但是其实际却是一个类;
就使用而言:“仿函数”更贴切:这种东西可以像函数一样被调用,通过function可以调用,也可以通过operator重载,重载形式是“operator()”;仿函数有多种分类。多种功能。这里只使用其比较功能
5.1:内置类型实现比较自由
具体代码如下所示:
template <class T>//仿函数,排降序
struct less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template <class T>
struct greater//仿函数,排升序;
{
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
{
public:
compare com;
//向上调整建大堆:
void adjust_up(int child)
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
//if (_pq[child] > _pq[parent])
if (com(_pq[parent], _pq[child]))
{
swap(_pq[child], _pq[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void push(const T& x)
{
_pq.push_back(x);
adjust_up(_pq.size() - 1);
}
//向下调整保持堆形:
void adjust_down(int parent)
{
size_t child = parent * 2 + 1;
while (child < _pq.size())
{
//if (child + 1 < _pq.size() && (_pq[child] < _pq[child + 1]))
if (child + 1 < _pq.size() && com(_pq[child], _pq[child + 1]))
{
++child;
}
//if (_pq[parent]<_pq[child])
if (com(_pq[parent], _pq[child]))
{
swap(_pq[child], _pq[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void pop()
{
swap(_pq[0], _pq[_pq.size() - 1]);
_pq.pop_back();
adjust_down(0);
}
const T& top()
{
return _pq[0];
}
size_t size()
{
return _pq.size();
}
bool empty()
{
return _pq.empty();
}
private:
container _pq;
};
void test_priority_queue()
{
priority_queue<int, vector<int>> pq;//默认排降序
//priority_queue<int, vector<int>, greater<int>> pq;//指定greater仿函数,排升序;
pq.push(1);
pq.push(12);
pq.push(3);
pq.push(10);
pq.push(21);
pq.push(5);
pq.push(9);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
}
///
5.2:自定义类型实现比较自由:
因为是自定义类型,所以只有在自定义类型中重载">" "<" 号才能使用仿函数比较:
具体代码如下所示:
template<class T, class container = vector<T>, class compare = less<T>>
class priority_queue
{
public:
compare com;
//向上调整建大堆:
void adjust_up(int child)
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
//if (_pq[child] > _pq[parent])
if (com(_pq[parent], _pq[child]))
{
swap(_pq[child], _pq[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void push(const T& x)
{
_pq.push_back(x);
adjust_up(_pq.size() - 1);
}
//向下调整保持堆形:
void adjust_down(int parent)
{
size_t child = parent * 2 + 1;
while (child < _pq.size())
{
//if (child + 1 < _pq.size() && (_pq[child] < _pq[child + 1]))
if (child + 1 < _pq.size() && com(_pq[child], _pq[child + 1]))
{
++child;
}
//if (_pq[parent]<_pq[child])
if (com(_pq[parent], _pq[child]))
{
swap(_pq[child], _pq[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void pop()
{
swap(_pq[0], _pq[_pq.size() - 1]);
_pq.pop_back();
adjust_down(0);
}
const T& top()
{
return _pq[0];
}
size_t size()
{
return _pq.size();
}
bool empty()
{
return _pq.empty();
}
private:
container _pq;
};
//自定义类型日期类
class data
{
public:
data(int year = 1900,int month = 4,int day = 3)
:_year(year)
, _month(month)
, _day(day)
{
}
重载'<'与'>'
bool operator<(const data& d1)const
{
return (_year < d1._year) ||
(_year == d1._year && _month < d1._month) ||
(_year == d1._year && _month == d1._month && _day < d1._day);
}
bool operator>(const data& d1)const
{
return (_year > d1._year) ||
(_year == d1._year && _month > d1._month) ||
(_year == d1._year && _month == d1._month && _day > d1._day);
}
friend ostream& operator<<(ostream& _cout, const data& d1)
{
_cout << d1._year << "-" << d1._month << "-" << d1._day << endl;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
struct dataless//自定义类型仿函数,排降序;
{
public:
bool operator()(const data* p1, const data* p2)
{
return *p1 < *p2;
}
};
struct datagreater//自定义类型仿函数,排升序;
{
public:
bool operator()(const data* p1, const data* p2)
{
return *p1 > *p2;
}
};
void test_priority_queue2()
{
//priority_queue<data> pq1;//默认排降序,拿到最大的日期
priority_queue<data,vector<data>,greater<data>> pq1;//指定排升序,拿到最小的日期
pq1.push(data(2023, 4, 1));
pq1.push(data(2023, 4, 2));
pq1.push(data(2023, 4, 3));
pq1.push(data(2023, 4, 4));
cout << pq1.top() << endl;
}
///
5.3:自定义类型的指针类型:
当我们比较的不是单纯的日期类时,变成日期类的指针时,此时需要通过泛型模板将比较控制在自己手中;
template<class T, class container = vector<T>, class compare = less<T>>
class priority_queue
{
public:
compare com;
//向上调整建大堆:
void adjust_up(int child)
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
//if (_pq[child] > _pq[parent])
if (com(_pq[parent], _pq[child]))
{
swap(_pq[child], _pq[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void push(const T& x)
{
_pq.push_back(x);
adjust_up(_pq.size() - 1);
}
//向下调整保持堆形:
void adjust_down(int parent)
{
size_t child = parent * 2 + 1;
while (child < _pq.size())
{
//if (child + 1 < _pq.size() && (_pq[child] < _pq[child + 1]))
if (child + 1 < _pq.size() && com(_pq[child], _pq[child + 1]))
{
++child;
}
//if (_pq[parent]<_pq[child])
if (com(_pq[parent], _pq[child]))
{
swap(_pq[child], _pq[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void pop()
{
swap(_pq[0], _pq[_pq.size() - 1]);
_pq.pop_back();
adjust_down(0);
}
const T& top()
{
return _pq[0];
}
size_t size()
{
return _pq.size();
}
bool empty()
{
return _pq.empty();
}
private:
container _pq;
};
class data
{
public:
data(int year = 1900,int month = 4,int day = 3)
:_year(year)
, _month(month)
, _day(day)
{
}
bool operator<(const data& d1)const
{
return (_year < d1._year) ||
(_year == d1._year && _month < d1._month) ||
(_year == d1._year && _month == d1._month && _day < d1._day);
}
bool operator>(const data& d1)const
{
return (_year > d1._year) ||
(_year == d1._year && _month > d1._month) ||
(_year == d1._year && _month == d1._month && _day > d1._day);
}
friend ostream& operator<<(ostream& _cout, const data& d1)
{
_cout << d1._year << "-" << d1._month << "-" << d1._day << endl;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
struct dataless
{
public:
template<class T>//泛型模板仿函数,排降序;
bool operator()(const T* p1, const T* p2)
{
return *p1 < *p2;
}
};
struct datagreater
{
public:
template<class T>//泛型模板仿函数,排升序;
bool operator()(const T* p1, const T* p2)
{
return *p1 > *p2;
}
};
void test_priority_queue3()
{
//priority_queue<data*,vector<data*>,dataless> pq2;//默认排降序,拿到最大的;
priority_queue<data*, vector<data*>, datagreater> pq2;//指定排升序,拿到最小的
pq2.push(new data(2023, 4, 1));
pq2.push(new data(2023, 4, 2));
pq2.push(new data(2023, 4, 3));
pq2.push(new data(2023, 4, 4));
cout << *(pq2.top()) << endl;
}
//////
至此,这是我对容器的相关概念的一些理解与使用,同时也是对优先级队列(priority_queue)的实现与如何控制排序的理解与使用,我将全部代码放到下方,请各位大佬指正!
#pragma once
#include <iostream>
#include <vector>
#include <list>
using namespace std;
//通过vector/list实现栈:
namespace MKL
{
//通过适配器模式实现,模板给个容器名称,容器名称可以任意,给缺省值,缺省值是容器,在此默认实现数组形式的栈:
template<class T,class container=vector<T>>
class stack
{
public:
void push(const T& x)//进栈:
{
_st.push_back(x);//调用模板中的容器的尾插接口,
}
void pop()//出栈:
{
_st.pop_back();//调用模板中的容器的尾删接口,
}
const T& top()//获取栈顶元素:
{
return _st.back();//调用模板中的容器的获取尾部元素接口,
}
size_t size()//栈中元素个数;
{
return _st.size();//调用模板中的容器的获取元素个数接口;
}
bool empty()//判断栈是否为空:
{
return _st.empty();//调用模板中的容器的是否为空接口;
}
private:
//通过模板中的容器来定义一个栈,此时,实现的是数组栈,所以是通过缺省值vector来定义的
//但是当模板中的容器发生改变时,调用不同的容器来定义,这个栈的性质就发生了根本变化;
container _st;
};
void test_stack1()
{
//数组栈:
//stack<int> st;//因为有缺省值vector,不写也不会报错,正常运行;
//stack<int, vector<int>> st;//也可以显示的写成所使用的容器;
//链式栈:
//只需要改变模板中的容器,那么栈的性质将发生改变改变;
stack<int, list<int>> st;//此时模板中的容器是list,所以实现的是链式栈;
st.push(1);
st.push(2);
st.push(3);
st.push(4);
st.push(5);
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
cout << endl;
}
}
//通过list实现队列
namespace MKL
{
template<class T,class container=list<T>>
class queue
{
public:
void push(const T& x)//进队列:
{
_qu.push_back(x);//调用模板中的容器的尾插接口,
}
void pop()//出队列
{
_qu.pop_front();调用模板中的容器的头删接口,
}
const T& top()//获取队头元素:
{
return _qu.front();//调用模板中的容器的获取头部元素接口,
}
const T& back()//获取队尾元素
{
return _qu.back();//调用模板中的容器的获取尾部元素接口,
}
bool empty()//判断队列是否为空:
{
return _qu.empty();//调用模板中的容器的是否为空接口;
}
private:
container _qu;//主要用容器list定义,
};
void test_queue1()
{
//因为队列需要队头出数据,所以vector就不适应于实现queue,
//实现queue主要靠list,list头插头删,任意地方插入删除效率高;
queue<int, list<int>> qu;
qu.push(1);
qu.push(2);
qu.push(3);
qu.push(4);
qu.push(5);
while (!qu.empty())
{
cout << qu.top() << " ";
qu.pop();
}
cout << endl;
}
}
namespace MKL
{
template <class T>//仿函数,排降序
struct less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template <class T>
struct greater//仿函数,排升序;
{
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
{
public:
compare com;
//向上调整建大堆:
void adjust_up(int child)
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
//if (_pq[child] > _pq[parent])
if (com(_pq[parent], _pq[child]))
{
swap(_pq[child], _pq[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void push(const T& x)
{
_pq.push_back(x);
adjust_up(_pq.size() - 1);
}
//向下调整保持堆形:
void adjust_down(int parent)
{
size_t child = parent * 2 + 1;
while (child < _pq.size())
{
//if (child + 1 < _pq.size() && (_pq[child] < _pq[child + 1]))
if (child + 1 < _pq.size() && com(_pq[child], _pq[child + 1]))
{
++child;
}
//if (_pq[parent]<_pq[child])
if (com(_pq[parent], _pq[child]))
{
swap(_pq[child], _pq[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void pop()
{
swap(_pq[0], _pq[_pq.size() - 1]);
_pq.pop_back();
adjust_down(0);
}
const T& top()
{
return _pq[0];
}
size_t size()
{
return _pq.size();
}
bool empty()
{
return _pq.empty();
}
private:
container _pq;
};
void test_priority_queue()
{
priority_queue<int, vector<int>> pq;//默认排降序
//priority_queue<int, vector<int>, greater<int>> pq;//指定greater仿函数,排升序;
pq.push(1);
pq.push(12);
pq.push(3);
pq.push(10);
pq.push(21);
pq.push(5);
pq.push(9);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
}
class data
{
public:
data(int year = 1900,int month = 4,int day = 3)
:_year(year)
, _month(month)
, _day(day)
{
}
bool operator<(const data& d1)const
{
return (_year < d1._year) ||
(_year == d1._year && _month < d1._month) ||
(_year == d1._year && _month == d1._month && _day < d1._day);
}
bool operator>(const data& d1)const
{
return (_year > d1._year) ||
(_year == d1._year && _month > d1._month) ||
(_year == d1._year && _month == d1._month && _day > d1._day);
}
friend ostream& operator<<(ostream& _cout, const data& d1)
{
_cout << d1._year << "-" << d1._month << "-" << d1._day << endl;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
struct dataless
{
public:
template<class T>
bool operator()(const T* p1, const T* p2)
{
return *p1 < *p2;
}
};
struct datagreater
{
public:
template<class T>
bool operator()(const T* p1, const T* p2)
{
return *p1 > *p2;
}
};
//struct dataless
//{
//public:
// bool operator()(const data* p1, const data* p2)
// {
// return *p1 < *p2;
// }
//};
//struct datagreater
//{
//public:
// bool operator()(const data* p1, const data* p2)
// {
// return *p1 > *p2;
// }
//};
void test_priority_queue2()
{
//priority_queue<data> pq1;
priority_queue<data,vector<data>,greater<data>> pq1;
pq1.push(data(2023, 4, 1));
pq1.push(data(2023, 4, 2));
pq1.push(data(2023, 4, 3));
pq1.push(data(2023, 4, 4));
cout << pq1.top() << endl;
}
void test_priority_queue3()
{
//priority_queue<data*,vector<data*>,dataless> pq2;
priority_queue<data*, vector<data*>, datagreater> pq2;
pq2.push(new data(2023, 4, 1));
pq2.push(new data(2023, 4, 2));
pq2.push(new data(2023, 4, 3));
pq2.push(new data(2023, 4, 4));
cout << *(pq2.top()) << endl;
}
}